Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
InstantMesh
Commits
63bde97a
Commit
63bde97a
authored
Aug 05, 2024
by
chenpangpang
Browse files
feat: 初始提交
parent
9cf8c6f1
Pipeline
#1475
failed with stages
in 0 seconds
Changes
94
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
3410 additions
and
0 deletions
+3410
-0
InstantMesh/src/models/encoder/dino_wrapper.py
InstantMesh/src/models/encoder/dino_wrapper.py
+80
-0
InstantMesh/src/models/geometry/__init__.py
InstantMesh/src/models/geometry/__init__.py
+7
-0
InstantMesh/src/models/geometry/camera/__init__.py
InstantMesh/src/models/geometry/camera/__init__.py
+16
-0
InstantMesh/src/models/geometry/camera/perspective_camera.py
InstantMesh/src/models/geometry/camera/perspective_camera.py
+35
-0
InstantMesh/src/models/geometry/render/__init__.py
InstantMesh/src/models/geometry/render/__init__.py
+8
-0
InstantMesh/src/models/geometry/render/neural_render.py
InstantMesh/src/models/geometry/render/neural_render.py
+121
-0
InstantMesh/src/models/geometry/rep_3d/__init__.py
InstantMesh/src/models/geometry/rep_3d/__init__.py
+18
-0
InstantMesh/src/models/geometry/rep_3d/dmtet.py
InstantMesh/src/models/geometry/rep_3d/dmtet.py
+504
-0
InstantMesh/src/models/geometry/rep_3d/dmtet_utils.py
InstantMesh/src/models/geometry/rep_3d/dmtet_utils.py
+20
-0
InstantMesh/src/models/geometry/rep_3d/extract_texture_map.py
...antMesh/src/models/geometry/rep_3d/extract_texture_map.py
+40
-0
InstantMesh/src/models/geometry/rep_3d/flexicubes.py
InstantMesh/src/models/geometry/rep_3d/flexicubes.py
+579
-0
InstantMesh/src/models/geometry/rep_3d/flexicubes_geometry.py
...antMesh/src/models/geometry/rep_3d/flexicubes_geometry.py
+120
-0
InstantMesh/src/models/geometry/rep_3d/tables.py
InstantMesh/src/models/geometry/rep_3d/tables.py
+791
-0
InstantMesh/src/models/lrm.py
InstantMesh/src/models/lrm.py
+209
-0
InstantMesh/src/models/lrm_mesh.py
InstantMesh/src/models/lrm_mesh.py
+382
-0
InstantMesh/src/models/renderer/__init__.py
InstantMesh/src/models/renderer/__init__.py
+9
-0
InstantMesh/src/models/renderer/synthesizer.py
InstantMesh/src/models/renderer/synthesizer.py
+203
-0
InstantMesh/src/models/renderer/synthesizer_mesh.py
InstantMesh/src/models/renderer/synthesizer_mesh.py
+141
-0
InstantMesh/src/models/renderer/utils/__init__.py
InstantMesh/src/models/renderer/utils/__init__.py
+9
-0
InstantMesh/src/models/renderer/utils/math_utils.py
InstantMesh/src/models/renderer/utils/math_utils.py
+118
-0
No files found.
InstantMesh/src/models/encoder/dino_wrapper.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2023, Zexin He
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import
torch.nn
as
nn
from
transformers
import
ViTImageProcessor
from
einops
import
rearrange
,
repeat
from
.dino
import
ViTModel
class
DinoWrapper
(
nn
.
Module
):
"""
Dino v1 wrapper using huggingface transformer implementation.
"""
def
__init__
(
self
,
model_name
:
str
,
freeze
:
bool
=
True
):
super
().
__init__
()
self
.
model
,
self
.
processor
=
self
.
_build_dino
(
model_name
)
self
.
camera_embedder
=
nn
.
Sequential
(
nn
.
Linear
(
16
,
self
.
model
.
config
.
hidden_size
,
bias
=
True
),
nn
.
SiLU
(),
nn
.
Linear
(
self
.
model
.
config
.
hidden_size
,
self
.
model
.
config
.
hidden_size
,
bias
=
True
)
)
if
freeze
:
self
.
_freeze
()
def
forward
(
self
,
image
,
camera
):
# image: [B, N, C, H, W]
# camera: [B, N, D]
# RGB image with [0,1] scale and properly sized
if
image
.
ndim
==
5
:
image
=
rearrange
(
image
,
'b n c h w -> (b n) c h w'
)
dtype
=
image
.
dtype
inputs
=
self
.
processor
(
images
=
image
.
float
(),
return_tensors
=
"pt"
,
do_rescale
=
False
,
do_resize
=
False
,
).
to
(
self
.
model
.
device
).
to
(
dtype
)
# embed camera
N
=
camera
.
shape
[
1
]
camera_embeddings
=
self
.
camera_embedder
(
camera
)
camera_embeddings
=
rearrange
(
camera_embeddings
,
'b n d -> (b n) d'
)
embeddings
=
camera_embeddings
# This resampling of positional embedding uses bicubic interpolation
outputs
=
self
.
model
(
**
inputs
,
adaln_input
=
embeddings
,
interpolate_pos_encoding
=
True
)
last_hidden_states
=
outputs
.
last_hidden_state
return
last_hidden_states
def
_freeze
(
self
):
print
(
f
"======== Freezing DinoWrapper ========"
)
self
.
model
.
eval
()
for
name
,
param
in
self
.
model
.
named_parameters
():
param
.
requires_grad
=
False
@
staticmethod
def
_build_dino
(
model_name
:
str
,
proxy_error_retries
:
int
=
3
,
proxy_error_cooldown
:
int
=
5
):
import
requests
try
:
model
=
ViTModel
.
from_pretrained
(
model_name
,
add_pooling_layer
=
False
)
processor
=
ViTImageProcessor
.
from_pretrained
(
model_name
)
return
model
,
processor
except
requests
.
exceptions
.
ProxyError
as
err
:
if
proxy_error_retries
>
0
:
print
(
f
"Huggingface ProxyError: Retrying in
{
proxy_error_cooldown
}
seconds..."
)
import
time
time
.
sleep
(
proxy_error_cooldown
)
return
DinoWrapper
.
_build_dino
(
model_name
,
proxy_error_retries
-
1
,
proxy_error_cooldown
)
else
:
raise
err
InstantMesh/src/models/geometry/__init__.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
InstantMesh/src/models/geometry/camera/__init__.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
from
torch
import
nn
class
Camera
(
nn
.
Module
):
def
__init__
(
self
):
super
(
Camera
,
self
).
__init__
()
pass
InstantMesh/src/models/geometry/camera/perspective_camera.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
from
.
import
Camera
import
numpy
as
np
def
projection
(
x
=
0.1
,
n
=
1.0
,
f
=
50.0
,
near_plane
=
None
):
if
near_plane
is
None
:
near_plane
=
n
return
np
.
array
(
[[
n
/
x
,
0
,
0
,
0
],
[
0
,
n
/
-
x
,
0
,
0
],
[
0
,
0
,
-
(
f
+
near_plane
)
/
(
f
-
near_plane
),
-
(
2
*
f
*
near_plane
)
/
(
f
-
near_plane
)],
[
0
,
0
,
-
1
,
0
]]).
astype
(
np
.
float32
)
class
PerspectiveCamera
(
Camera
):
def
__init__
(
self
,
fovy
=
49.0
,
device
=
'cuda'
):
super
(
PerspectiveCamera
,
self
).
__init__
()
self
.
device
=
device
focal
=
np
.
tan
(
fovy
/
180.0
*
np
.
pi
*
0.5
)
self
.
proj_mtx
=
torch
.
from_numpy
(
projection
(
x
=
focal
,
f
=
1000.0
,
n
=
1.0
,
near_plane
=
0.1
)).
to
(
self
.
device
).
unsqueeze
(
dim
=
0
)
def
project
(
self
,
points_bxnx4
):
out
=
torch
.
matmul
(
points_bxnx4
,
torch
.
transpose
(
self
.
proj_mtx
,
1
,
2
))
return
out
InstantMesh/src/models/geometry/render/__init__.py
0 → 100644
View file @
63bde97a
import
torch
class
Renderer
():
def
__init__
(
self
):
pass
def
forward
(
self
):
pass
\ No newline at end of file
InstantMesh/src/models/geometry/render/neural_render.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
import
torch.nn.functional
as
F
import
nvdiffrast.torch
as
dr
from
.
import
Renderer
_FG_LUT
=
None
def
interpolate
(
attr
,
rast
,
attr_idx
,
rast_db
=
None
):
return
dr
.
interpolate
(
attr
.
contiguous
(),
rast
,
attr_idx
,
rast_db
=
rast_db
,
diff_attrs
=
None
if
rast_db
is
None
else
'all'
)
def
xfm_points
(
points
,
matrix
,
use_python
=
True
):
'''Transform points.
Args:
points: Tensor containing 3D points with shape [minibatch_size, num_vertices, 3] or [1, num_vertices, 3]
matrix: A 4x4 transform matrix with shape [minibatch_size, 4, 4]
use_python: Use PyTorch's torch.matmul (for validation)
Returns:
Transformed points in homogeneous 4D with shape [minibatch_size, num_vertices, 4].
'''
out
=
torch
.
matmul
(
torch
.
nn
.
functional
.
pad
(
points
,
pad
=
(
0
,
1
),
mode
=
'constant'
,
value
=
1.0
),
torch
.
transpose
(
matrix
,
1
,
2
))
if
torch
.
is_anomaly_enabled
():
assert
torch
.
all
(
torch
.
isfinite
(
out
)),
"Output of xfm_points contains inf or NaN"
return
out
def
dot
(
x
,
y
):
return
torch
.
sum
(
x
*
y
,
-
1
,
keepdim
=
True
)
def
compute_vertex_normal
(
v_pos
,
t_pos_idx
):
i0
=
t_pos_idx
[:,
0
]
i1
=
t_pos_idx
[:,
1
]
i2
=
t_pos_idx
[:,
2
]
v0
=
v_pos
[
i0
,
:]
v1
=
v_pos
[
i1
,
:]
v2
=
v_pos
[
i2
,
:]
face_normals
=
torch
.
cross
(
v1
-
v0
,
v2
-
v0
)
# Splat face normals to vertices
v_nrm
=
torch
.
zeros_like
(
v_pos
)
v_nrm
.
scatter_add_
(
0
,
i0
[:,
None
].
repeat
(
1
,
3
),
face_normals
)
v_nrm
.
scatter_add_
(
0
,
i1
[:,
None
].
repeat
(
1
,
3
),
face_normals
)
v_nrm
.
scatter_add_
(
0
,
i2
[:,
None
].
repeat
(
1
,
3
),
face_normals
)
# Normalize, replace zero (degenerated) normals with some default value
v_nrm
=
torch
.
where
(
dot
(
v_nrm
,
v_nrm
)
>
1e-20
,
v_nrm
,
torch
.
as_tensor
([
0.0
,
0.0
,
1.0
]).
to
(
v_nrm
)
)
v_nrm
=
F
.
normalize
(
v_nrm
,
dim
=
1
)
assert
torch
.
all
(
torch
.
isfinite
(
v_nrm
))
return
v_nrm
class
NeuralRender
(
Renderer
):
def
__init__
(
self
,
device
=
'cuda'
,
camera_model
=
None
):
super
(
NeuralRender
,
self
).
__init__
()
self
.
device
=
device
self
.
ctx
=
dr
.
RasterizeCudaContext
(
device
=
device
)
self
.
projection_mtx
=
None
self
.
camera
=
camera_model
def
render_mesh
(
self
,
mesh_v_pos_bxnx3
,
mesh_t_pos_idx_fx3
,
camera_mv_bx4x4
,
mesh_v_feat_bxnxd
,
resolution
=
256
,
spp
=
1
,
device
=
'cuda'
,
hierarchical_mask
=
False
):
assert
not
hierarchical_mask
mtx_in
=
torch
.
tensor
(
camera_mv_bx4x4
,
dtype
=
torch
.
float32
,
device
=
device
)
if
not
torch
.
is_tensor
(
camera_mv_bx4x4
)
else
camera_mv_bx4x4
v_pos
=
xfm_points
(
mesh_v_pos_bxnx3
,
mtx_in
)
# Rotate it to camera coordinates
v_pos_clip
=
self
.
camera
.
project
(
v_pos
)
# Projection in the camera
v_nrm
=
compute_vertex_normal
(
mesh_v_pos_bxnx3
[
0
],
mesh_t_pos_idx_fx3
.
long
())
# vertex normals in world coordinates
# Render the image,
# Here we only return the feature (3D location) at each pixel, which will be used as the input for neural render
num_layers
=
1
mask_pyramid
=
None
assert
mesh_t_pos_idx_fx3
.
shape
[
0
]
>
0
# Make sure we have shapes
mesh_v_feat_bxnxd
=
torch
.
cat
([
mesh_v_feat_bxnxd
.
repeat
(
v_pos
.
shape
[
0
],
1
,
1
),
v_pos
],
dim
=-
1
)
# Concatenate the pos
with
dr
.
DepthPeeler
(
self
.
ctx
,
v_pos_clip
,
mesh_t_pos_idx_fx3
,
[
resolution
*
spp
,
resolution
*
spp
])
as
peeler
:
for
_
in
range
(
num_layers
):
rast
,
db
=
peeler
.
rasterize_next_layer
()
gb_feat
,
_
=
interpolate
(
mesh_v_feat_bxnxd
,
rast
,
mesh_t_pos_idx_fx3
)
hard_mask
=
torch
.
clamp
(
rast
[...,
-
1
:],
0
,
1
)
antialias_mask
=
dr
.
antialias
(
hard_mask
.
clone
().
contiguous
(),
rast
,
v_pos_clip
,
mesh_t_pos_idx_fx3
)
depth
=
gb_feat
[...,
-
2
:
-
1
]
ori_mesh_feature
=
gb_feat
[...,
:
-
4
]
normal
,
_
=
interpolate
(
v_nrm
[
None
,
...],
rast
,
mesh_t_pos_idx_fx3
)
normal
=
dr
.
antialias
(
normal
.
clone
().
contiguous
(),
rast
,
v_pos_clip
,
mesh_t_pos_idx_fx3
)
normal
=
F
.
normalize
(
normal
,
dim
=-
1
)
normal
=
torch
.
lerp
(
torch
.
zeros_like
(
normal
),
(
normal
+
1.0
)
/
2.0
,
hard_mask
.
float
())
# black background
return
ori_mesh_feature
,
antialias_mask
,
hard_mask
,
rast
,
v_pos_clip
,
mask_pyramid
,
depth
,
normal
InstantMesh/src/models/geometry/rep_3d/__init__.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
import
numpy
as
np
class
Geometry
():
def
__init__
(
self
):
pass
def
forward
(
self
):
pass
InstantMesh/src/models/geometry/rep_3d/dmtet.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
import
numpy
as
np
import
os
from
.
import
Geometry
from
.dmtet_utils
import
get_center_boundary_index
import
torch.nn.functional
as
F
###############################################################################
# DMTet utility functions
###############################################################################
def
create_mt_variable
(
device
):
triangle_table
=
torch
.
tensor
(
[
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
0
,
2
,
-
1
,
-
1
,
-
1
],
[
4
,
0
,
3
,
-
1
,
-
1
,
-
1
],
[
1
,
4
,
2
,
1
,
3
,
4
],
[
3
,
1
,
5
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
0
,
2
,
5
,
3
],
[
1
,
4
,
0
,
1
,
5
,
4
],
[
4
,
2
,
5
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
2
,
-
1
,
-
1
,
-
1
],
[
4
,
1
,
0
,
4
,
5
,
1
],
[
3
,
2
,
0
,
3
,
5
,
2
],
[
1
,
3
,
5
,
-
1
,
-
1
,
-
1
],
[
4
,
1
,
2
,
4
,
3
,
1
],
[
3
,
0
,
4
,
-
1
,
-
1
,
-
1
],
[
2
,
0
,
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]
],
dtype
=
torch
.
long
,
device
=
device
)
num_triangles_table
=
torch
.
tensor
([
0
,
1
,
1
,
2
,
1
,
2
,
2
,
1
,
1
,
2
,
2
,
1
,
2
,
1
,
1
,
0
],
dtype
=
torch
.
long
,
device
=
device
)
base_tet_edges
=
torch
.
tensor
([
0
,
1
,
0
,
2
,
0
,
3
,
1
,
2
,
1
,
3
,
2
,
3
],
dtype
=
torch
.
long
,
device
=
device
)
v_id
=
torch
.
pow
(
2
,
torch
.
arange
(
4
,
dtype
=
torch
.
long
,
device
=
device
))
return
triangle_table
,
num_triangles_table
,
base_tet_edges
,
v_id
def
sort_edges
(
edges_ex2
):
with
torch
.
no_grad
():
order
=
(
edges_ex2
[:,
0
]
>
edges_ex2
[:,
1
]).
long
()
order
=
order
.
unsqueeze
(
dim
=
1
)
a
=
torch
.
gather
(
input
=
edges_ex2
,
index
=
order
,
dim
=
1
)
b
=
torch
.
gather
(
input
=
edges_ex2
,
index
=
1
-
order
,
dim
=
1
)
return
torch
.
stack
([
a
,
b
],
-
1
)
###############################################################################
# marching tetrahedrons (differentiable)
###############################################################################
def
marching_tets
(
pos_nx3
,
sdf_n
,
tet_fx4
,
triangle_table
,
num_triangles_table
,
base_tet_edges
,
v_id
):
with
torch
.
no_grad
():
occ_n
=
sdf_n
>
0
occ_fx4
=
occ_n
[
tet_fx4
.
reshape
(
-
1
)].
reshape
(
-
1
,
4
)
occ_sum
=
torch
.
sum
(
occ_fx4
,
-
1
)
valid_tets
=
(
occ_sum
>
0
)
&
(
occ_sum
<
4
)
occ_sum
=
occ_sum
[
valid_tets
]
# find all vertices
all_edges
=
tet_fx4
[
valid_tets
][:,
base_tet_edges
].
reshape
(
-
1
,
2
)
all_edges
=
sort_edges
(
all_edges
)
unique_edges
,
idx_map
=
torch
.
unique
(
all_edges
,
dim
=
0
,
return_inverse
=
True
)
unique_edges
=
unique_edges
.
long
()
mask_edges
=
occ_n
[
unique_edges
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
).
sum
(
-
1
)
==
1
mapping
=
torch
.
ones
((
unique_edges
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
sdf_n
.
device
)
*
-
1
mapping
[
mask_edges
]
=
torch
.
arange
(
mask_edges
.
sum
(),
dtype
=
torch
.
long
,
device
=
sdf_n
.
device
)
idx_map
=
mapping
[
idx_map
]
# map edges to verts
interp_v
=
unique_edges
[
mask_edges
]
# .long()
edges_to_interp
=
pos_nx3
[
interp_v
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
,
3
)
edges_to_interp_sdf
=
sdf_n
[
interp_v
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
,
1
)
edges_to_interp_sdf
[:,
-
1
]
*=
-
1
denominator
=
edges_to_interp_sdf
.
sum
(
1
,
keepdim
=
True
)
edges_to_interp_sdf
=
torch
.
flip
(
edges_to_interp_sdf
,
[
1
])
/
denominator
verts
=
(
edges_to_interp
*
edges_to_interp_sdf
).
sum
(
1
)
idx_map
=
idx_map
.
reshape
(
-
1
,
6
)
tetindex
=
(
occ_fx4
[
valid_tets
]
*
v_id
.
unsqueeze
(
0
)).
sum
(
-
1
)
num_triangles
=
num_triangles_table
[
tetindex
]
# Generate triangle indices
faces
=
torch
.
cat
(
(
torch
.
gather
(
input
=
idx_map
[
num_triangles
==
1
],
dim
=
1
,
index
=
triangle_table
[
tetindex
[
num_triangles
==
1
]][:,
:
3
]).
reshape
(
-
1
,
3
),
torch
.
gather
(
input
=
idx_map
[
num_triangles
==
2
],
dim
=
1
,
index
=
triangle_table
[
tetindex
[
num_triangles
==
2
]][:,
:
6
]).
reshape
(
-
1
,
3
),
),
dim
=
0
)
return
verts
,
faces
def
create_tetmesh_variables
(
device
=
'cuda'
):
tet_table
=
torch
.
tensor
(
[[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
0
,
4
,
5
,
6
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
0
,
8
,
7
,
0
,
5
,
8
,
7
,
0
,
5
,
6
,
8
],
[
2
,
5
,
7
,
9
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
0
,
9
,
7
,
0
,
4
,
9
,
7
,
0
,
4
,
6
,
9
],
[
2
,
1
,
9
,
5
,
1
,
4
,
9
,
5
,
1
,
4
,
8
,
9
],
[
6
,
0
,
1
,
2
,
6
,
1
,
2
,
8
,
6
,
8
,
2
,
9
],
[
3
,
6
,
8
,
9
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
3
,
0
,
9
,
8
,
0
,
4
,
9
,
8
,
0
,
4
,
5
,
9
],
[
3
,
1
,
9
,
6
,
1
,
4
,
9
,
6
,
1
,
4
,
7
,
9
],
[
5
,
0
,
1
,
3
,
5
,
1
,
3
,
7
,
5
,
7
,
3
,
9
],
[
3
,
2
,
8
,
6
,
2
,
5
,
8
,
6
,
2
,
5
,
7
,
8
],
[
4
,
0
,
2
,
3
,
4
,
2
,
3
,
7
,
4
,
7
,
3
,
8
],
[
4
,
1
,
2
,
3
,
4
,
2
,
3
,
5
,
4
,
5
,
3
,
6
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
dtype
=
torch
.
long
,
device
=
device
)
num_tets_table
=
torch
.
tensor
([
0
,
1
,
1
,
3
,
1
,
3
,
3
,
3
,
1
,
3
,
3
,
3
,
3
,
3
,
3
,
0
],
dtype
=
torch
.
long
,
device
=
device
)
return
tet_table
,
num_tets_table
def
marching_tets_tetmesh
(
pos_nx3
,
sdf_n
,
tet_fx4
,
triangle_table
,
num_triangles_table
,
base_tet_edges
,
v_id
,
return_tet_mesh
=
False
,
ori_v
=
None
,
num_tets_table
=
None
,
tet_table
=
None
):
with
torch
.
no_grad
():
occ_n
=
sdf_n
>
0
occ_fx4
=
occ_n
[
tet_fx4
.
reshape
(
-
1
)].
reshape
(
-
1
,
4
)
occ_sum
=
torch
.
sum
(
occ_fx4
,
-
1
)
valid_tets
=
(
occ_sum
>
0
)
&
(
occ_sum
<
4
)
occ_sum
=
occ_sum
[
valid_tets
]
# find all vertices
all_edges
=
tet_fx4
[
valid_tets
][:,
base_tet_edges
].
reshape
(
-
1
,
2
)
all_edges
=
sort_edges
(
all_edges
)
unique_edges
,
idx_map
=
torch
.
unique
(
all_edges
,
dim
=
0
,
return_inverse
=
True
)
unique_edges
=
unique_edges
.
long
()
mask_edges
=
occ_n
[
unique_edges
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
).
sum
(
-
1
)
==
1
mapping
=
torch
.
ones
((
unique_edges
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
sdf_n
.
device
)
*
-
1
mapping
[
mask_edges
]
=
torch
.
arange
(
mask_edges
.
sum
(),
dtype
=
torch
.
long
,
device
=
sdf_n
.
device
)
idx_map
=
mapping
[
idx_map
]
# map edges to verts
interp_v
=
unique_edges
[
mask_edges
]
# .long()
edges_to_interp
=
pos_nx3
[
interp_v
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
,
3
)
edges_to_interp_sdf
=
sdf_n
[
interp_v
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
,
1
)
edges_to_interp_sdf
[:,
-
1
]
*=
-
1
denominator
=
edges_to_interp_sdf
.
sum
(
1
,
keepdim
=
True
)
edges_to_interp_sdf
=
torch
.
flip
(
edges_to_interp_sdf
,
[
1
])
/
denominator
verts
=
(
edges_to_interp
*
edges_to_interp_sdf
).
sum
(
1
)
idx_map
=
idx_map
.
reshape
(
-
1
,
6
)
tetindex
=
(
occ_fx4
[
valid_tets
]
*
v_id
.
unsqueeze
(
0
)).
sum
(
-
1
)
num_triangles
=
num_triangles_table
[
tetindex
]
# Generate triangle indices
faces
=
torch
.
cat
(
(
torch
.
gather
(
input
=
idx_map
[
num_triangles
==
1
],
dim
=
1
,
index
=
triangle_table
[
tetindex
[
num_triangles
==
1
]][:,
:
3
]).
reshape
(
-
1
,
3
),
torch
.
gather
(
input
=
idx_map
[
num_triangles
==
2
],
dim
=
1
,
index
=
triangle_table
[
tetindex
[
num_triangles
==
2
]][:,
:
6
]).
reshape
(
-
1
,
3
),
),
dim
=
0
)
if
not
return_tet_mesh
:
return
verts
,
faces
occupied_verts
=
ori_v
[
occ_n
]
mapping
=
torch
.
ones
((
pos_nx3
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
"cuda"
)
*
-
1
mapping
[
occ_n
]
=
torch
.
arange
(
occupied_verts
.
shape
[
0
],
device
=
"cuda"
)
tet_fx4
=
mapping
[
tet_fx4
.
reshape
(
-
1
)].
reshape
((
-
1
,
4
))
idx_map
=
torch
.
cat
([
tet_fx4
[
valid_tets
]
+
verts
.
shape
[
0
],
idx_map
],
-
1
)
# t x 10
tet_verts
=
torch
.
cat
([
verts
,
occupied_verts
],
0
)
num_tets
=
num_tets_table
[
tetindex
]
tets
=
torch
.
cat
(
(
torch
.
gather
(
input
=
idx_map
[
num_tets
==
1
],
dim
=
1
,
index
=
tet_table
[
tetindex
[
num_tets
==
1
]][:,
:
4
]).
reshape
(
-
1
,
4
),
torch
.
gather
(
input
=
idx_map
[
num_tets
==
3
],
dim
=
1
,
index
=
tet_table
[
tetindex
[
num_tets
==
3
]][:,
:
12
]).
reshape
(
-
1
,
4
),
),
dim
=
0
)
# add fully occupied tets
fully_occupied
=
occ_fx4
.
sum
(
-
1
)
==
4
tet_fully_occupied
=
tet_fx4
[
fully_occupied
]
+
verts
.
shape
[
0
]
tets
=
torch
.
cat
([
tets
,
tet_fully_occupied
])
return
verts
,
faces
,
tet_verts
,
tets
###############################################################################
# Compact tet grid
###############################################################################
def
compact_tets
(
pos_nx3
,
sdf_n
,
tet_fx4
):
with
torch
.
no_grad
():
# Find surface tets
occ_n
=
sdf_n
>
0
occ_fx4
=
occ_n
[
tet_fx4
.
reshape
(
-
1
)].
reshape
(
-
1
,
4
)
occ_sum
=
torch
.
sum
(
occ_fx4
,
-
1
)
valid_tets
=
(
occ_sum
>
0
)
&
(
occ_sum
<
4
)
# one value per tet, these are the surface tets
valid_vtx
=
tet_fx4
[
valid_tets
].
reshape
(
-
1
)
unique_vtx
,
idx_map
=
torch
.
unique
(
valid_vtx
,
dim
=
0
,
return_inverse
=
True
)
new_pos
=
pos_nx3
[
unique_vtx
]
new_sdf
=
sdf_n
[
unique_vtx
]
new_tets
=
idx_map
.
reshape
(
-
1
,
4
)
return
new_pos
,
new_sdf
,
new_tets
###############################################################################
# Subdivide volume
###############################################################################
def
batch_subdivide_volume
(
tet_pos_bxnx3
,
tet_bxfx4
,
grid_sdf
):
device
=
tet_pos_bxnx3
.
device
# get new verts
tet_fx4
=
tet_bxfx4
[
0
]
edges
=
[
0
,
1
,
0
,
2
,
0
,
3
,
1
,
2
,
1
,
3
,
2
,
3
]
all_edges
=
tet_fx4
[:,
edges
].
reshape
(
-
1
,
2
)
all_edges
=
sort_edges
(
all_edges
)
unique_edges
,
idx_map
=
torch
.
unique
(
all_edges
,
dim
=
0
,
return_inverse
=
True
)
idx_map
=
idx_map
+
tet_pos_bxnx3
.
shape
[
1
]
all_values
=
torch
.
cat
([
tet_pos_bxnx3
,
grid_sdf
],
-
1
)
mid_points_pos
=
all_values
[:,
unique_edges
.
reshape
(
-
1
)].
reshape
(
all_values
.
shape
[
0
],
-
1
,
2
,
all_values
.
shape
[
-
1
]).
mean
(
2
)
new_v
=
torch
.
cat
([
all_values
,
mid_points_pos
],
1
)
new_v
,
new_sdf
=
new_v
[...,
:
3
],
new_v
[...,
3
]
# get new tets
idx_a
,
idx_b
,
idx_c
,
idx_d
=
tet_fx4
[:,
0
],
tet_fx4
[:,
1
],
tet_fx4
[:,
2
],
tet_fx4
[:,
3
]
idx_ab
=
idx_map
[
0
::
6
]
idx_ac
=
idx_map
[
1
::
6
]
idx_ad
=
idx_map
[
2
::
6
]
idx_bc
=
idx_map
[
3
::
6
]
idx_bd
=
idx_map
[
4
::
6
]
idx_cd
=
idx_map
[
5
::
6
]
tet_1
=
torch
.
stack
([
idx_a
,
idx_ab
,
idx_ac
,
idx_ad
],
dim
=
1
)
tet_2
=
torch
.
stack
([
idx_b
,
idx_bc
,
idx_ab
,
idx_bd
],
dim
=
1
)
tet_3
=
torch
.
stack
([
idx_c
,
idx_ac
,
idx_bc
,
idx_cd
],
dim
=
1
)
tet_4
=
torch
.
stack
([
idx_d
,
idx_ad
,
idx_cd
,
idx_bd
],
dim
=
1
)
tet_5
=
torch
.
stack
([
idx_ab
,
idx_ac
,
idx_ad
,
idx_bd
],
dim
=
1
)
tet_6
=
torch
.
stack
([
idx_ab
,
idx_ac
,
idx_bd
,
idx_bc
],
dim
=
1
)
tet_7
=
torch
.
stack
([
idx_cd
,
idx_ac
,
idx_bd
,
idx_ad
],
dim
=
1
)
tet_8
=
torch
.
stack
([
idx_cd
,
idx_ac
,
idx_bc
,
idx_bd
],
dim
=
1
)
tet_np
=
torch
.
cat
([
tet_1
,
tet_2
,
tet_3
,
tet_4
,
tet_5
,
tet_6
,
tet_7
,
tet_8
],
dim
=
0
)
tet_np
=
tet_np
.
reshape
(
1
,
-
1
,
4
).
expand
(
tet_pos_bxnx3
.
shape
[
0
],
-
1
,
-
1
)
tet
=
tet_np
.
long
().
to
(
device
)
return
new_v
,
tet
,
new_sdf
###############################################################################
# Adjacency
###############################################################################
def
tet_to_tet_adj_sparse
(
tet_tx4
):
# include self connection!!!!!!!!!!!!!!!!!!!
with
torch
.
no_grad
():
t
=
tet_tx4
.
shape
[
0
]
device
=
tet_tx4
.
device
idx_array
=
torch
.
LongTensor
(
[
0
,
1
,
2
,
1
,
0
,
3
,
2
,
3
,
0
,
3
,
2
,
1
]).
to
(
device
).
reshape
(
4
,
3
).
unsqueeze
(
0
).
expand
(
t
,
-
1
,
-
1
)
# (t, 4, 3)
# get all faces
all_faces
=
torch
.
gather
(
input
=
tet_tx4
.
unsqueeze
(
1
).
expand
(
-
1
,
4
,
-
1
),
index
=
idx_array
,
dim
=-
1
).
reshape
(
-
1
,
3
)
# (tx4, 3)
all_faces_tet_idx
=
torch
.
arange
(
t
,
device
=
device
).
unsqueeze
(
-
1
).
expand
(
-
1
,
4
).
reshape
(
-
1
)
# sort and group
all_faces_sorted
,
_
=
torch
.
sort
(
all_faces
,
dim
=
1
)
all_faces_unique
,
inverse_indices
,
counts
=
torch
.
unique
(
all_faces_sorted
,
dim
=
0
,
return_counts
=
True
,
return_inverse
=
True
)
tet_face_fx3
=
all_faces_unique
[
counts
==
2
]
counts
=
counts
[
inverse_indices
]
# tx4
valid
=
(
counts
==
2
)
group
=
inverse_indices
[
valid
]
# print (inverse_indices.shape, group.shape, all_faces_tet_idx.shape)
_
,
indices
=
torch
.
sort
(
group
)
all_faces_tet_idx_grouped
=
all_faces_tet_idx
[
valid
][
indices
]
tet_face_tetidx_fx2
=
torch
.
stack
([
all_faces_tet_idx_grouped
[::
2
],
all_faces_tet_idx_grouped
[
1
::
2
]],
dim
=-
1
)
tet_adj_idx
=
torch
.
cat
([
tet_face_tetidx_fx2
,
torch
.
flip
(
tet_face_tetidx_fx2
,
[
1
])])
adj_self
=
torch
.
arange
(
t
,
device
=
tet_tx4
.
device
)
adj_self
=
torch
.
stack
([
adj_self
,
adj_self
],
-
1
)
tet_adj_idx
=
torch
.
cat
([
tet_adj_idx
,
adj_self
])
tet_adj_idx
=
torch
.
unique
(
tet_adj_idx
,
dim
=
0
)
values
=
torch
.
ones
(
tet_adj_idx
.
shape
[
0
],
device
=
tet_tx4
.
device
).
float
()
adj_sparse
=
torch
.
sparse
.
FloatTensor
(
tet_adj_idx
.
t
(),
values
,
torch
.
Size
([
t
,
t
]))
# normalization
neighbor_num
=
1.0
/
torch
.
sparse
.
sum
(
adj_sparse
,
dim
=
1
).
to_dense
()
values
=
torch
.
index_select
(
neighbor_num
,
0
,
tet_adj_idx
[:,
0
])
adj_sparse
=
torch
.
sparse
.
FloatTensor
(
tet_adj_idx
.
t
(),
values
,
torch
.
Size
([
t
,
t
]))
return
adj_sparse
###############################################################################
# Compact grid
###############################################################################
def
get_tet_bxfx4x3
(
bxnxz
,
bxfx4
):
n_batch
,
z
=
bxnxz
.
shape
[
0
],
bxnxz
.
shape
[
2
]
gather_input
=
bxnxz
.
unsqueeze
(
2
).
expand
(
n_batch
,
bxnxz
.
shape
[
1
],
4
,
z
)
gather_index
=
bxfx4
.
unsqueeze
(
-
1
).
expand
(
n_batch
,
bxfx4
.
shape
[
1
],
4
,
z
).
long
()
tet_bxfx4xz
=
torch
.
gather
(
input
=
gather_input
,
dim
=
1
,
index
=
gather_index
)
return
tet_bxfx4xz
def
shrink_grid
(
tet_pos_bxnx3
,
tet_bxfx4
,
grid_sdf
):
with
torch
.
no_grad
():
assert
tet_pos_bxnx3
.
shape
[
0
]
==
1
occ
=
grid_sdf
[
0
]
>
0
occ_sum
=
get_tet_bxfx4x3
(
occ
.
unsqueeze
(
0
).
unsqueeze
(
-
1
),
tet_bxfx4
).
reshape
(
-
1
,
4
).
sum
(
-
1
)
mask
=
(
occ_sum
>
0
)
&
(
occ_sum
<
4
)
# build connectivity graph
adj_matrix
=
tet_to_tet_adj_sparse
(
tet_bxfx4
[
0
])
mask
=
mask
.
float
().
unsqueeze
(
-
1
)
# Include a one ring of neighbors
for
i
in
range
(
1
):
mask
=
torch
.
sparse
.
mm
(
adj_matrix
,
mask
)
mask
=
mask
.
squeeze
(
-
1
)
>
0
mapping
=
torch
.
zeros
((
tet_pos_bxnx3
.
shape
[
1
]),
device
=
tet_pos_bxnx3
.
device
,
dtype
=
torch
.
long
)
new_tet_bxfx4
=
tet_bxfx4
[:,
mask
].
long
()
selected_verts_idx
=
torch
.
unique
(
new_tet_bxfx4
)
new_tet_pos_bxnx3
=
tet_pos_bxnx3
[:,
selected_verts_idx
]
mapping
[
selected_verts_idx
]
=
torch
.
arange
(
selected_verts_idx
.
shape
[
0
],
device
=
tet_pos_bxnx3
.
device
)
new_tet_bxfx4
=
mapping
[
new_tet_bxfx4
.
reshape
(
-
1
)].
reshape
(
new_tet_bxfx4
.
shape
)
new_grid_sdf
=
grid_sdf
[:,
selected_verts_idx
]
return
new_tet_pos_bxnx3
,
new_tet_bxfx4
,
new_grid_sdf
###############################################################################
# Regularizer
###############################################################################
def
sdf_reg_loss
(
sdf
,
all_edges
):
sdf_f1x6x2
=
sdf
[
all_edges
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
)
mask
=
torch
.
sign
(
sdf_f1x6x2
[...,
0
])
!=
torch
.
sign
(
sdf_f1x6x2
[...,
1
])
sdf_f1x6x2
=
sdf_f1x6x2
[
mask
]
sdf_diff
=
torch
.
nn
.
functional
.
binary_cross_entropy_with_logits
(
sdf_f1x6x2
[...,
0
],
(
sdf_f1x6x2
[...,
1
]
>
0
).
float
())
+
\
torch
.
nn
.
functional
.
binary_cross_entropy_with_logits
(
sdf_f1x6x2
[...,
1
],
(
sdf_f1x6x2
[...,
0
]
>
0
).
float
())
return
sdf_diff
def
sdf_reg_loss_batch
(
sdf
,
all_edges
):
sdf_f1x6x2
=
sdf
[:,
all_edges
.
reshape
(
-
1
)].
reshape
(
sdf
.
shape
[
0
],
-
1
,
2
)
mask
=
torch
.
sign
(
sdf_f1x6x2
[...,
0
])
!=
torch
.
sign
(
sdf_f1x6x2
[...,
1
])
sdf_f1x6x2
=
sdf_f1x6x2
[
mask
]
sdf_diff
=
torch
.
nn
.
functional
.
binary_cross_entropy_with_logits
(
sdf_f1x6x2
[...,
0
],
(
sdf_f1x6x2
[...,
1
]
>
0
).
float
())
+
\
torch
.
nn
.
functional
.
binary_cross_entropy_with_logits
(
sdf_f1x6x2
[...,
1
],
(
sdf_f1x6x2
[...,
0
]
>
0
).
float
())
return
sdf_diff
###############################################################################
# Geometry interface
###############################################################################
class
DMTetGeometry
(
Geometry
):
def
__init__
(
self
,
grid_res
=
64
,
scale
=
2.0
,
device
=
'cuda'
,
renderer
=
None
,
render_type
=
'neural_render'
,
args
=
None
):
super
(
DMTetGeometry
,
self
).
__init__
()
self
.
grid_res
=
grid_res
self
.
device
=
device
self
.
args
=
args
tets
=
np
.
load
(
'data/tets/%d_compress.npz'
%
(
grid_res
))
self
.
verts
=
torch
.
from_numpy
(
tets
[
'vertices'
]).
float
().
to
(
self
.
device
)
# Make sure the tet is zero-centered and length is equal to 1
length
=
self
.
verts
.
max
(
dim
=
0
)[
0
]
-
self
.
verts
.
min
(
dim
=
0
)[
0
]
length
=
length
.
max
()
mid
=
(
self
.
verts
.
max
(
dim
=
0
)[
0
]
+
self
.
verts
.
min
(
dim
=
0
)[
0
])
/
2.0
self
.
verts
=
(
self
.
verts
-
mid
.
unsqueeze
(
dim
=
0
))
/
length
if
isinstance
(
scale
,
list
):
self
.
verts
[:,
0
]
=
self
.
verts
[:,
0
]
*
scale
[
0
]
self
.
verts
[:,
1
]
=
self
.
verts
[:,
1
]
*
scale
[
1
]
self
.
verts
[:,
2
]
=
self
.
verts
[:,
2
]
*
scale
[
1
]
else
:
self
.
verts
=
self
.
verts
*
scale
self
.
indices
=
torch
.
from_numpy
(
tets
[
'tets'
]).
long
().
to
(
self
.
device
)
self
.
triangle_table
,
self
.
num_triangles_table
,
self
.
base_tet_edges
,
self
.
v_id
=
create_mt_variable
(
self
.
device
)
self
.
tet_table
,
self
.
num_tets_table
=
create_tetmesh_variables
(
self
.
device
)
# Parameters for regularization computation
edges
=
torch
.
tensor
([
0
,
1
,
0
,
2
,
0
,
3
,
1
,
2
,
1
,
3
,
2
,
3
],
dtype
=
torch
.
long
,
device
=
self
.
device
)
all_edges
=
self
.
indices
[:,
edges
].
reshape
(
-
1
,
2
)
all_edges_sorted
=
torch
.
sort
(
all_edges
,
dim
=
1
)[
0
]
self
.
all_edges
=
torch
.
unique
(
all_edges_sorted
,
dim
=
0
)
# Parameters used for fix boundary sdf
self
.
center_indices
,
self
.
boundary_indices
=
get_center_boundary_index
(
self
.
verts
)
self
.
renderer
=
renderer
self
.
render_type
=
render_type
def
getAABB
(
self
):
return
torch
.
min
(
self
.
verts
,
dim
=
0
).
values
,
torch
.
max
(
self
.
verts
,
dim
=
0
).
values
def
get_mesh
(
self
,
v_deformed_nx3
,
sdf_n
,
with_uv
=
False
,
indices
=
None
):
if
indices
is
None
:
indices
=
self
.
indices
verts
,
faces
=
marching_tets
(
v_deformed_nx3
,
sdf_n
,
indices
,
self
.
triangle_table
,
self
.
num_triangles_table
,
self
.
base_tet_edges
,
self
.
v_id
)
faces
=
torch
.
cat
(
[
faces
[:,
0
:
1
],
faces
[:,
2
:
3
],
faces
[:,
1
:
2
],
],
dim
=-
1
)
return
verts
,
faces
def
get_tet_mesh
(
self
,
v_deformed_nx3
,
sdf_n
,
with_uv
=
False
,
indices
=
None
):
if
indices
is
None
:
indices
=
self
.
indices
verts
,
faces
,
tet_verts
,
tets
=
marching_tets_tetmesh
(
v_deformed_nx3
,
sdf_n
,
indices
,
self
.
triangle_table
,
self
.
num_triangles_table
,
self
.
base_tet_edges
,
self
.
v_id
,
return_tet_mesh
=
True
,
num_tets_table
=
self
.
num_tets_table
,
tet_table
=
self
.
tet_table
,
ori_v
=
v_deformed_nx3
)
faces
=
torch
.
cat
(
[
faces
[:,
0
:
1
],
faces
[:,
2
:
3
],
faces
[:,
1
:
2
],
],
dim
=-
1
)
return
verts
,
faces
,
tet_verts
,
tets
def
render_mesh
(
self
,
mesh_v_nx3
,
mesh_f_fx3
,
camera_mv_bx4x4
,
resolution
=
256
,
hierarchical_mask
=
False
):
return_value
=
dict
()
if
self
.
render_type
==
'neural_render'
:
tex_pos
,
mask
,
hard_mask
,
rast
,
v_pos_clip
,
mask_pyramid
,
depth
=
self
.
renderer
.
render_mesh
(
mesh_v_nx3
.
unsqueeze
(
dim
=
0
),
mesh_f_fx3
.
int
(),
camera_mv_bx4x4
,
mesh_v_nx3
.
unsqueeze
(
dim
=
0
),
resolution
=
resolution
,
device
=
self
.
device
,
hierarchical_mask
=
hierarchical_mask
)
return_value
[
'tex_pos'
]
=
tex_pos
return_value
[
'mask'
]
=
mask
return_value
[
'hard_mask'
]
=
hard_mask
return_value
[
'rast'
]
=
rast
return_value
[
'v_pos_clip'
]
=
v_pos_clip
return_value
[
'mask_pyramid'
]
=
mask_pyramid
return_value
[
'depth'
]
=
depth
else
:
raise
NotImplementedError
return
return_value
def
render
(
self
,
v_deformed_bxnx3
=
None
,
sdf_bxn
=
None
,
camera_mv_bxnviewx4x4
=
None
,
resolution
=
256
):
# Here I assume a batch of meshes (can be different mesh and geometry), for the other shapes, the batch is 1
v_list
=
[]
f_list
=
[]
n_batch
=
v_deformed_bxnx3
.
shape
[
0
]
all_render_output
=
[]
for
i_batch
in
range
(
n_batch
):
verts_nx3
,
faces_fx3
=
self
.
get_mesh
(
v_deformed_bxnx3
[
i_batch
],
sdf_bxn
[
i_batch
])
v_list
.
append
(
verts_nx3
)
f_list
.
append
(
faces_fx3
)
render_output
=
self
.
render_mesh
(
verts_nx3
,
faces_fx3
,
camera_mv_bxnviewx4x4
[
i_batch
],
resolution
)
all_render_output
.
append
(
render_output
)
# Concatenate all render output
return_keys
=
all_render_output
[
0
].
keys
()
return_value
=
dict
()
for
k
in
return_keys
:
value
=
[
v
[
k
]
for
v
in
all_render_output
]
return_value
[
k
]
=
value
# We can do concatenation outside of the render
return
return_value
InstantMesh/src/models/geometry/rep_3d/dmtet_utils.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
def
get_center_boundary_index
(
verts
):
length_
=
torch
.
sum
(
verts
**
2
,
dim
=-
1
)
center_idx
=
torch
.
argmin
(
length_
)
boundary_neg
=
verts
==
verts
.
max
()
boundary_pos
=
verts
==
verts
.
min
()
boundary
=
torch
.
bitwise_or
(
boundary_pos
,
boundary_neg
)
boundary
=
torch
.
sum
(
boundary
.
float
(),
dim
=-
1
)
boundary_idx
=
torch
.
nonzero
(
boundary
)
return
center_idx
,
boundary_idx
.
squeeze
(
dim
=-
1
)
InstantMesh/src/models/geometry/rep_3d/extract_texture_map.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
import
xatlas
import
numpy
as
np
import
nvdiffrast.torch
as
dr
# ==============================================================================================
def
interpolate
(
attr
,
rast
,
attr_idx
,
rast_db
=
None
):
return
dr
.
interpolate
(
attr
.
contiguous
(),
rast
,
attr_idx
,
rast_db
=
rast_db
,
diff_attrs
=
None
if
rast_db
is
None
else
'all'
)
def
xatlas_uvmap
(
ctx
,
mesh_v
,
mesh_pos_idx
,
resolution
):
vmapping
,
indices
,
uvs
=
xatlas
.
parametrize
(
mesh_v
.
detach
().
cpu
().
numpy
(),
mesh_pos_idx
.
detach
().
cpu
().
numpy
())
# Convert to tensors
indices_int64
=
indices
.
astype
(
np
.
uint64
,
casting
=
'same_kind'
).
view
(
np
.
int64
)
uvs
=
torch
.
tensor
(
uvs
,
dtype
=
torch
.
float32
,
device
=
mesh_v
.
device
)
mesh_tex_idx
=
torch
.
tensor
(
indices_int64
,
dtype
=
torch
.
int64
,
device
=
mesh_v
.
device
)
# mesh_v_tex. ture
uv_clip
=
uvs
[
None
,
...]
*
2.0
-
1.0
# pad to four component coordinate
uv_clip4
=
torch
.
cat
((
uv_clip
,
torch
.
zeros_like
(
uv_clip
[...,
0
:
1
]),
torch
.
ones_like
(
uv_clip
[...,
0
:
1
])),
dim
=-
1
)
# rasterize
rast
,
_
=
dr
.
rasterize
(
ctx
,
uv_clip4
,
mesh_tex_idx
.
int
(),
(
resolution
,
resolution
))
# Interpolate world space position
gb_pos
,
_
=
interpolate
(
mesh_v
[
None
,
...],
rast
,
mesh_pos_idx
.
int
())
mask
=
rast
[...,
3
:
4
]
>
0
return
uvs
,
mesh_tex_idx
,
gb_pos
,
mask
InstantMesh/src/models/geometry/rep_3d/flexicubes.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
from
.tables
import
*
__all__
=
[
'FlexiCubes'
]
class
FlexiCubes
:
"""
This class implements the FlexiCubes method for extracting meshes from scalar fields.
It maintains a series of lookup tables and indices to support the mesh extraction process.
FlexiCubes, a differentiable variant of the Dual Marching Cubes (DMC) scheme, enhances
the geometric fidelity and mesh quality of reconstructed meshes by dynamically adjusting
the surface representation through gradient-based optimization.
During instantiation, the class loads DMC tables from a file and transforms them into
PyTorch tensors on the specified device.
Attributes:
device (str): Specifies the computational device (default is "cuda").
dmc_table (torch.Tensor): Dual Marching Cubes (DMC) table that encodes the edges
associated with each dual vertex in 256 Marching Cubes (MC) configurations.
num_vd_table (torch.Tensor): Table holding the number of dual vertices in each of
the 256 MC configurations.
check_table (torch.Tensor): Table resolving ambiguity in cases C16 and C19
of the DMC configurations.
tet_table (torch.Tensor): Lookup table used in tetrahedralizing the isosurface.
quad_split_1 (torch.Tensor): Indices for splitting a quad into two triangles
along one diagonal.
quad_split_2 (torch.Tensor): Alternative indices for splitting a quad into
two triangles along the other diagonal.
quad_split_train (torch.Tensor): Indices for splitting a quad into four triangles
during training by connecting all edges to their midpoints.
cube_corners (torch.Tensor): Defines the positions of a standard unit cube's
eight corners in 3D space, ordered starting from the origin (0,0,0),
moving along the x-axis, then y-axis, and finally z-axis.
Used as a blueprint for generating a voxel grid.
cube_corners_idx (torch.Tensor): Cube corners indexed as powers of 2, used
to retrieve the case id.
cube_edges (torch.Tensor): Edge connections in a cube, listed in pairs.
Used to retrieve edge vertices in DMC.
edge_dir_table (torch.Tensor): A mapping tensor that associates edge indices with
their corresponding axis. For instance, edge_dir_table[0] = 0 indicates that the
first edge is oriented along the x-axis.
dir_faces_table (torch.Tensor): A tensor that maps the corresponding axis of shared edges
across four adjacent cubes to the shared faces of these cubes. For instance,
dir_faces_table[0] = [5, 4] implies that for four cubes sharing an edge along
the x-axis, the first and second cubes share faces indexed as 5 and 4, respectively.
This tensor is only utilized during isosurface tetrahedralization.
adj_pairs (torch.Tensor):
A tensor containing index pairs that correspond to neighboring cubes that share the same edge.
qef_reg_scale (float):
The scaling factor applied to the regularization loss to prevent issues with singularity
when solving the QEF. This parameter is only used when a 'grad_func' is specified.
weight_scale (float):
The scale of weights in FlexiCubes. Should be between 0 and 1.
"""
def
__init__
(
self
,
device
=
"cuda"
,
qef_reg_scale
=
1e-3
,
weight_scale
=
0.99
):
self
.
device
=
device
self
.
dmc_table
=
torch
.
tensor
(
dmc_table
,
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
num_vd_table
=
torch
.
tensor
(
num_vd_table
,
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
check_table
=
torch
.
tensor
(
check_table
,
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
tet_table
=
torch
.
tensor
(
tet_table
,
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
quad_split_1
=
torch
.
tensor
([
0
,
1
,
2
,
0
,
2
,
3
],
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
quad_split_2
=
torch
.
tensor
([
0
,
1
,
3
,
3
,
1
,
2
],
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
quad_split_train
=
torch
.
tensor
(
[
0
,
1
,
1
,
2
,
2
,
3
,
3
,
0
],
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
cube_corners
=
torch
.
tensor
([[
0
,
0
,
0
],
[
1
,
0
,
0
],
[
0
,
1
,
0
],
[
1
,
1
,
0
],
[
0
,
0
,
1
],
[
1
,
0
,
1
],
[
0
,
1
,
1
],
[
1
,
1
,
1
]],
dtype
=
torch
.
float
,
device
=
device
)
self
.
cube_corners_idx
=
torch
.
pow
(
2
,
torch
.
arange
(
8
,
requires_grad
=
False
))
self
.
cube_edges
=
torch
.
tensor
([
0
,
1
,
1
,
5
,
4
,
5
,
0
,
4
,
2
,
3
,
3
,
7
,
6
,
7
,
2
,
6
,
2
,
0
,
3
,
1
,
7
,
5
,
6
,
4
],
dtype
=
torch
.
long
,
device
=
device
,
requires_grad
=
False
)
self
.
edge_dir_table
=
torch
.
tensor
([
0
,
2
,
0
,
2
,
0
,
2
,
0
,
2
,
1
,
1
,
1
,
1
],
dtype
=
torch
.
long
,
device
=
device
)
self
.
dir_faces_table
=
torch
.
tensor
([
[[
5
,
4
],
[
3
,
2
],
[
4
,
5
],
[
2
,
3
]],
[[
5
,
4
],
[
1
,
0
],
[
4
,
5
],
[
0
,
1
]],
[[
3
,
2
],
[
1
,
0
],
[
2
,
3
],
[
0
,
1
]]
],
dtype
=
torch
.
long
,
device
=
device
)
self
.
adj_pairs
=
torch
.
tensor
([
0
,
1
,
1
,
3
,
3
,
2
,
2
,
0
],
dtype
=
torch
.
long
,
device
=
device
)
self
.
qef_reg_scale
=
qef_reg_scale
self
.
weight_scale
=
weight_scale
def
construct_voxel_grid
(
self
,
res
):
"""
Generates a voxel grid based on the specified resolution.
Args:
res (int or list[int]): The resolution of the voxel grid. If an integer
is provided, it is used for all three dimensions. If a list or tuple
of 3 integers is provided, they define the resolution for the x,
y, and z dimensions respectively.
Returns:
(torch.Tensor, torch.Tensor): Returns the vertices and the indices of the
cube corners (index into vertices) of the constructed voxel grid.
The vertices are centered at the origin, with the length of each
dimension in the grid being one.
"""
base_cube_f
=
torch
.
arange
(
8
).
to
(
self
.
device
)
if
isinstance
(
res
,
int
):
res
=
(
res
,
res
,
res
)
voxel_grid_template
=
torch
.
ones
(
res
,
device
=
self
.
device
)
res
=
torch
.
tensor
([
res
],
dtype
=
torch
.
float
,
device
=
self
.
device
)
coords
=
torch
.
nonzero
(
voxel_grid_template
).
float
()
/
res
# N, 3
verts
=
(
self
.
cube_corners
.
unsqueeze
(
0
)
/
res
+
coords
.
unsqueeze
(
1
)).
reshape
(
-
1
,
3
)
cubes
=
(
base_cube_f
.
unsqueeze
(
0
)
+
torch
.
arange
(
coords
.
shape
[
0
],
device
=
self
.
device
).
unsqueeze
(
1
)
*
8
).
reshape
(
-
1
)
verts_rounded
=
torch
.
round
(
verts
*
10
**
5
)
/
(
10
**
5
)
verts_unique
,
inverse_indices
=
torch
.
unique
(
verts_rounded
,
dim
=
0
,
return_inverse
=
True
)
cubes
=
inverse_indices
[
cubes
.
reshape
(
-
1
)].
reshape
(
-
1
,
8
)
return
verts_unique
-
0.5
,
cubes
def
__call__
(
self
,
x_nx3
,
s_n
,
cube_fx8
,
res
,
beta_fx12
=
None
,
alpha_fx8
=
None
,
gamma_f
=
None
,
training
=
False
,
output_tetmesh
=
False
,
grad_func
=
None
):
r
"""
Main function for mesh extraction from scalar field using FlexiCubes. This function converts
discrete signed distance fields, encoded on voxel grids and additional per-cube parameters,
to triangle or tetrahedral meshes using a differentiable operation as described in
`Flexible Isosurface Extraction for Gradient-Based Mesh Optimization`_. FlexiCubes enhances
mesh quality and geometric fidelity by adjusting the surface representation based on gradient
optimization. The output surface is differentiable with respect to the input vertex positions,
scalar field values, and weight parameters.
If you intend to extract a surface mesh from a fixed Signed Distance Field without the
optimization of parameters, it is suggested to provide the "grad_func" which should
return the surface gradient at any given 3D position. When grad_func is provided, the process
to determine the dual vertex position adapts to solve a Quadratic Error Function (QEF), as
described in the `Manifold Dual Contouring`_ paper, and employs an smart splitting strategy.
Please note, this approach is non-differentiable.
For more details and example usage in optimization, refer to the
`Flexible Isosurface Extraction for Gradient-Based Mesh Optimization`_ SIGGRAPH 2023 paper.
Args:
x_nx3 (torch.Tensor): Coordinates of the voxel grid vertices, can be deformed.
s_n (torch.Tensor): Scalar field values at each vertex of the voxel grid. Negative values
denote that the corresponding vertex resides inside the isosurface. This affects
the directions of the extracted triangle faces and volume to be tetrahedralized.
cube_fx8 (torch.Tensor): Indices of 8 vertices for each cube in the voxel grid.
res (int or list[int]): The resolution of the voxel grid. If an integer is provided, it
is used for all three dimensions. If a list or tuple of 3 integers is provided, they
specify the resolution for the x, y, and z dimensions respectively.
beta_fx12 (torch.Tensor, optional): Weight parameters for the cube edges to adjust dual
vertices positioning. Defaults to uniform value for all edges.
alpha_fx8 (torch.Tensor, optional): Weight parameters for the cube corners to adjust dual
vertices positioning. Defaults to uniform value for all vertices.
gamma_f (torch.Tensor, optional): Weight parameters to control the splitting of
quadrilaterals into triangles. Defaults to uniform value for all cubes.
training (bool, optional): If set to True, applies differentiable quad splitting for
training. Defaults to False.
output_tetmesh (bool, optional): If set to True, outputs a tetrahedral mesh, otherwise,
outputs a triangular mesh. Defaults to False.
grad_func (callable, optional): A function to compute the surface gradient at specified
3D positions (input: Nx3 positions). The function should return gradients as an Nx3
tensor. If None, the original FlexiCubes algorithm is utilized. Defaults to None.
Returns:
(torch.Tensor, torch.LongTensor, torch.Tensor): Tuple containing:
- Vertices for the extracted triangular/tetrahedral mesh.
- Faces for the extracted triangular/tetrahedral mesh.
- Regularizer L_dev, computed per dual vertex.
.. _Flexible Isosurface Extraction for Gradient-Based Mesh Optimization:
https://research.nvidia.com/labs/toronto-ai/flexicubes/
.. _Manifold Dual Contouring:
https://people.engr.tamu.edu/schaefer/research/dualsimp_tvcg.pdf
"""
surf_cubes
,
occ_fx8
=
self
.
_identify_surf_cubes
(
s_n
,
cube_fx8
)
if
surf_cubes
.
sum
()
==
0
:
return
torch
.
zeros
(
(
0
,
3
),
device
=
self
.
device
),
torch
.
zeros
(
(
0
,
4
),
dtype
=
torch
.
long
,
device
=
self
.
device
)
if
output_tetmesh
else
torch
.
zeros
(
(
0
,
3
),
dtype
=
torch
.
long
,
device
=
self
.
device
),
torch
.
zeros
(
(
0
),
device
=
self
.
device
)
beta_fx12
,
alpha_fx8
,
gamma_f
=
self
.
_normalize_weights
(
beta_fx12
,
alpha_fx8
,
gamma_f
,
surf_cubes
)
case_ids
=
self
.
_get_case_id
(
occ_fx8
,
surf_cubes
,
res
)
surf_edges
,
idx_map
,
edge_counts
,
surf_edges_mask
=
self
.
_identify_surf_edges
(
s_n
,
cube_fx8
,
surf_cubes
)
vd
,
L_dev
,
vd_gamma
,
vd_idx_map
=
self
.
_compute_vd
(
x_nx3
,
cube_fx8
[
surf_cubes
],
surf_edges
,
s_n
,
case_ids
,
beta_fx12
,
alpha_fx8
,
gamma_f
,
idx_map
,
grad_func
)
vertices
,
faces
,
s_edges
,
edge_indices
=
self
.
_triangulate
(
s_n
,
surf_edges
,
vd
,
vd_gamma
,
edge_counts
,
idx_map
,
vd_idx_map
,
surf_edges_mask
,
training
,
grad_func
)
if
not
output_tetmesh
:
return
vertices
,
faces
,
L_dev
else
:
vertices
,
tets
=
self
.
_tetrahedralize
(
x_nx3
,
s_n
,
cube_fx8
,
vertices
,
faces
,
surf_edges
,
s_edges
,
vd_idx_map
,
case_ids
,
edge_indices
,
surf_cubes
,
training
)
return
vertices
,
tets
,
L_dev
def
_compute_reg_loss
(
self
,
vd
,
ue
,
edge_group_to_vd
,
vd_num_edges
):
"""
Regularizer L_dev as in Equation 8
"""
dist
=
torch
.
norm
(
ue
-
torch
.
index_select
(
input
=
vd
,
index
=
edge_group_to_vd
,
dim
=
0
),
dim
=-
1
)
mean_l2
=
torch
.
zeros_like
(
vd
[:,
0
])
mean_l2
=
(
mean_l2
).
index_add_
(
0
,
edge_group_to_vd
,
dist
)
/
vd_num_edges
.
squeeze
(
1
).
float
()
mad
=
(
dist
-
torch
.
index_select
(
input
=
mean_l2
,
index
=
edge_group_to_vd
,
dim
=
0
)).
abs
()
return
mad
def
_normalize_weights
(
self
,
beta_fx12
,
alpha_fx8
,
gamma_f
,
surf_cubes
):
"""
Normalizes the given weights to be non-negative. If input weights are None, it creates and returns a set of weights of ones.
"""
n_cubes
=
surf_cubes
.
shape
[
0
]
if
beta_fx12
is
not
None
:
beta_fx12
=
(
torch
.
tanh
(
beta_fx12
)
*
self
.
weight_scale
+
1
)
else
:
beta_fx12
=
torch
.
ones
((
n_cubes
,
12
),
dtype
=
torch
.
float
,
device
=
self
.
device
)
if
alpha_fx8
is
not
None
:
alpha_fx8
=
(
torch
.
tanh
(
alpha_fx8
)
*
self
.
weight_scale
+
1
)
else
:
alpha_fx8
=
torch
.
ones
((
n_cubes
,
8
),
dtype
=
torch
.
float
,
device
=
self
.
device
)
if
gamma_f
is
not
None
:
gamma_f
=
torch
.
sigmoid
(
gamma_f
)
*
self
.
weight_scale
+
(
1
-
self
.
weight_scale
)
/
2
else
:
gamma_f
=
torch
.
ones
((
n_cubes
),
dtype
=
torch
.
float
,
device
=
self
.
device
)
return
beta_fx12
[
surf_cubes
],
alpha_fx8
[
surf_cubes
],
gamma_f
[
surf_cubes
]
@
torch
.
no_grad
()
def
_get_case_id
(
self
,
occ_fx8
,
surf_cubes
,
res
):
"""
Obtains the ID of topology cases based on cell corner occupancy. This function resolves the
ambiguity in the Dual Marching Cubes (DMC) configurations as described in Section 1.3 of the
supplementary material. It should be noted that this function assumes a regular grid.
"""
case_ids
=
(
occ_fx8
[
surf_cubes
]
*
self
.
cube_corners_idx
.
to
(
self
.
device
).
unsqueeze
(
0
)).
sum
(
-
1
)
problem_config
=
self
.
check_table
.
to
(
self
.
device
)[
case_ids
]
to_check
=
problem_config
[...,
0
]
==
1
problem_config
=
problem_config
[
to_check
]
if
not
isinstance
(
res
,
(
list
,
tuple
)):
res
=
[
res
,
res
,
res
]
# The 'problematic_configs' only contain configurations for surface cubes. Next, we construct a 3D array,
# 'problem_config_full', to store configurations for all cubes (with default config for non-surface cubes).
# This allows efficient checking on adjacent cubes.
problem_config_full
=
torch
.
zeros
(
list
(
res
)
+
[
5
],
device
=
self
.
device
,
dtype
=
torch
.
long
)
vol_idx
=
torch
.
nonzero
(
problem_config_full
[...,
0
]
==
0
)
# N, 3
vol_idx_problem
=
vol_idx
[
surf_cubes
][
to_check
]
problem_config_full
[
vol_idx_problem
[...,
0
],
vol_idx_problem
[...,
1
],
vol_idx_problem
[...,
2
]]
=
problem_config
vol_idx_problem_adj
=
vol_idx_problem
+
problem_config
[...,
1
:
4
]
within_range
=
(
vol_idx_problem_adj
[...,
0
]
>=
0
)
&
(
vol_idx_problem_adj
[...,
0
]
<
res
[
0
])
&
(
vol_idx_problem_adj
[...,
1
]
>=
0
)
&
(
vol_idx_problem_adj
[...,
1
]
<
res
[
1
])
&
(
vol_idx_problem_adj
[...,
2
]
>=
0
)
&
(
vol_idx_problem_adj
[...,
2
]
<
res
[
2
])
vol_idx_problem
=
vol_idx_problem
[
within_range
]
vol_idx_problem_adj
=
vol_idx_problem_adj
[
within_range
]
problem_config
=
problem_config
[
within_range
]
problem_config_adj
=
problem_config_full
[
vol_idx_problem_adj
[...,
0
],
vol_idx_problem_adj
[...,
1
],
vol_idx_problem_adj
[...,
2
]]
# If two cubes with cases C16 and C19 share an ambiguous face, both cases are inverted.
to_invert
=
(
problem_config_adj
[...,
0
]
==
1
)
idx
=
torch
.
arange
(
case_ids
.
shape
[
0
],
device
=
self
.
device
)[
to_check
][
within_range
][
to_invert
]
case_ids
.
index_put_
((
idx
,),
problem_config
[
to_invert
][...,
-
1
])
return
case_ids
@
torch
.
no_grad
()
def
_identify_surf_edges
(
self
,
s_n
,
cube_fx8
,
surf_cubes
):
"""
Identifies grid edges that intersect with the underlying surface by checking for opposite signs. As each edge
can be shared by multiple cubes, this function also assigns a unique index to each surface-intersecting edge
and marks the cube edges with this index.
"""
occ_n
=
s_n
<
0
all_edges
=
cube_fx8
[
surf_cubes
][:,
self
.
cube_edges
].
reshape
(
-
1
,
2
)
unique_edges
,
_idx_map
,
counts
=
torch
.
unique
(
all_edges
,
dim
=
0
,
return_inverse
=
True
,
return_counts
=
True
)
unique_edges
=
unique_edges
.
long
()
mask_edges
=
occ_n
[
unique_edges
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
).
sum
(
-
1
)
==
1
surf_edges_mask
=
mask_edges
[
_idx_map
]
counts
=
counts
[
_idx_map
]
mapping
=
torch
.
ones
((
unique_edges
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
cube_fx8
.
device
)
*
-
1
mapping
[
mask_edges
]
=
torch
.
arange
(
mask_edges
.
sum
(),
device
=
cube_fx8
.
device
)
# Shaped as [number of cubes x 12 edges per cube]. This is later used to map a cube edge to the unique index
# for a surface-intersecting edge. Non-surface-intersecting edges are marked with -1.
idx_map
=
mapping
[
_idx_map
]
surf_edges
=
unique_edges
[
mask_edges
]
return
surf_edges
,
idx_map
,
counts
,
surf_edges_mask
@
torch
.
no_grad
()
def
_identify_surf_cubes
(
self
,
s_n
,
cube_fx8
):
"""
Identifies grid cubes that intersect with the underlying surface by checking if the signs at
all corners are not identical.
"""
occ_n
=
s_n
<
0
occ_fx8
=
occ_n
[
cube_fx8
.
reshape
(
-
1
)].
reshape
(
-
1
,
8
)
_occ_sum
=
torch
.
sum
(
occ_fx8
,
-
1
)
surf_cubes
=
(
_occ_sum
>
0
)
&
(
_occ_sum
<
8
)
return
surf_cubes
,
occ_fx8
def
_linear_interp
(
self
,
edges_weight
,
edges_x
):
"""
Computes the location of zero-crossings on 'edges_x' using linear interpolation with 'edges_weight'.
"""
edge_dim
=
edges_weight
.
dim
()
-
2
assert
edges_weight
.
shape
[
edge_dim
]
==
2
edges_weight
=
torch
.
cat
([
torch
.
index_select
(
input
=
edges_weight
,
index
=
torch
.
tensor
(
1
,
device
=
self
.
device
),
dim
=
edge_dim
),
-
torch
.
index_select
(
input
=
edges_weight
,
index
=
torch
.
tensor
(
0
,
device
=
self
.
device
),
dim
=
edge_dim
)],
edge_dim
)
denominator
=
edges_weight
.
sum
(
edge_dim
)
ue
=
(
edges_x
*
edges_weight
).
sum
(
edge_dim
)
/
denominator
return
ue
def
_solve_vd_QEF
(
self
,
p_bxnx3
,
norm_bxnx3
,
c_bx3
=
None
):
p_bxnx3
=
p_bxnx3
.
reshape
(
-
1
,
7
,
3
)
norm_bxnx3
=
norm_bxnx3
.
reshape
(
-
1
,
7
,
3
)
c_bx3
=
c_bx3
.
reshape
(
-
1
,
3
)
A
=
norm_bxnx3
B
=
((
p_bxnx3
)
*
norm_bxnx3
).
sum
(
-
1
,
keepdims
=
True
)
A_reg
=
(
torch
.
eye
(
3
,
device
=
p_bxnx3
.
device
)
*
self
.
qef_reg_scale
).
unsqueeze
(
0
).
repeat
(
p_bxnx3
.
shape
[
0
],
1
,
1
)
B_reg
=
(
self
.
qef_reg_scale
*
c_bx3
).
unsqueeze
(
-
1
)
A
=
torch
.
cat
([
A
,
A_reg
],
1
)
B
=
torch
.
cat
([
B
,
B_reg
],
1
)
dual_verts
=
torch
.
linalg
.
lstsq
(
A
,
B
).
solution
.
squeeze
(
-
1
)
return
dual_verts
def
_compute_vd
(
self
,
x_nx3
,
surf_cubes_fx8
,
surf_edges
,
s_n
,
case_ids
,
beta_fx12
,
alpha_fx8
,
gamma_f
,
idx_map
,
grad_func
):
"""
Computes the location of dual vertices as described in Section 4.2
"""
alpha_nx12x2
=
torch
.
index_select
(
input
=
alpha_fx8
,
index
=
self
.
cube_edges
,
dim
=
1
).
reshape
(
-
1
,
12
,
2
)
surf_edges_x
=
torch
.
index_select
(
input
=
x_nx3
,
index
=
surf_edges
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
2
,
3
)
surf_edges_s
=
torch
.
index_select
(
input
=
s_n
,
index
=
surf_edges
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
2
,
1
)
zero_crossing
=
self
.
_linear_interp
(
surf_edges_s
,
surf_edges_x
)
idx_map
=
idx_map
.
reshape
(
-
1
,
12
)
num_vd
=
torch
.
index_select
(
input
=
self
.
num_vd_table
,
index
=
case_ids
,
dim
=
0
)
edge_group
,
edge_group_to_vd
,
edge_group_to_cube
,
vd_num_edges
,
vd_gamma
=
[],
[],
[],
[],
[]
total_num_vd
=
0
vd_idx_map
=
torch
.
zeros
((
case_ids
.
shape
[
0
],
12
),
dtype
=
torch
.
long
,
device
=
self
.
device
,
requires_grad
=
False
)
if
grad_func
is
not
None
:
normals
=
torch
.
nn
.
functional
.
normalize
(
grad_func
(
zero_crossing
),
dim
=-
1
)
vd
=
[]
for
num
in
torch
.
unique
(
num_vd
):
cur_cubes
=
(
num_vd
==
num
)
# consider cubes with the same numbers of vd emitted (for batching)
curr_num_vd
=
cur_cubes
.
sum
()
*
num
curr_edge_group
=
self
.
dmc_table
[
case_ids
[
cur_cubes
],
:
num
].
reshape
(
-
1
,
num
*
7
)
curr_edge_group_to_vd
=
torch
.
arange
(
curr_num_vd
,
device
=
self
.
device
).
unsqueeze
(
-
1
).
repeat
(
1
,
7
)
+
total_num_vd
total_num_vd
+=
curr_num_vd
curr_edge_group_to_cube
=
torch
.
arange
(
idx_map
.
shape
[
0
],
device
=
self
.
device
)[
cur_cubes
].
unsqueeze
(
-
1
).
repeat
(
1
,
num
*
7
).
reshape_as
(
curr_edge_group
)
curr_mask
=
(
curr_edge_group
!=
-
1
)
edge_group
.
append
(
torch
.
masked_select
(
curr_edge_group
,
curr_mask
))
edge_group_to_vd
.
append
(
torch
.
masked_select
(
curr_edge_group_to_vd
.
reshape_as
(
curr_edge_group
),
curr_mask
))
edge_group_to_cube
.
append
(
torch
.
masked_select
(
curr_edge_group_to_cube
,
curr_mask
))
vd_num_edges
.
append
(
curr_mask
.
reshape
(
-
1
,
7
).
sum
(
-
1
,
keepdims
=
True
))
vd_gamma
.
append
(
torch
.
masked_select
(
gamma_f
,
cur_cubes
).
unsqueeze
(
-
1
).
repeat
(
1
,
num
).
reshape
(
-
1
))
if
grad_func
is
not
None
:
with
torch
.
no_grad
():
cube_e_verts_idx
=
idx_map
[
cur_cubes
]
curr_edge_group
[
~
curr_mask
]
=
0
verts_group_idx
=
torch
.
gather
(
input
=
cube_e_verts_idx
,
dim
=
1
,
index
=
curr_edge_group
)
verts_group_idx
[
verts_group_idx
==
-
1
]
=
0
verts_group_pos
=
torch
.
index_select
(
input
=
zero_crossing
,
index
=
verts_group_idx
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
num
.
item
(),
7
,
3
)
v0
=
x_nx3
[
surf_cubes_fx8
[
cur_cubes
][:,
0
]].
reshape
(
-
1
,
1
,
1
,
3
).
repeat
(
1
,
num
.
item
(),
1
,
1
)
curr_mask
=
curr_mask
.
reshape
(
-
1
,
num
.
item
(),
7
,
1
)
verts_centroid
=
(
verts_group_pos
*
curr_mask
).
sum
(
2
)
/
(
curr_mask
.
sum
(
2
))
normals_bx7x3
=
torch
.
index_select
(
input
=
normals
,
index
=
verts_group_idx
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
num
.
item
(),
7
,
3
)
curr_mask
=
curr_mask
.
squeeze
(
2
)
vd
.
append
(
self
.
_solve_vd_QEF
((
verts_group_pos
-
v0
)
*
curr_mask
,
normals_bx7x3
*
curr_mask
,
verts_centroid
-
v0
.
squeeze
(
2
))
+
v0
.
reshape
(
-
1
,
3
))
edge_group
=
torch
.
cat
(
edge_group
)
edge_group_to_vd
=
torch
.
cat
(
edge_group_to_vd
)
edge_group_to_cube
=
torch
.
cat
(
edge_group_to_cube
)
vd_num_edges
=
torch
.
cat
(
vd_num_edges
)
vd_gamma
=
torch
.
cat
(
vd_gamma
)
if
grad_func
is
not
None
:
vd
=
torch
.
cat
(
vd
)
L_dev
=
torch
.
zeros
([
1
],
device
=
self
.
device
)
else
:
vd
=
torch
.
zeros
((
total_num_vd
,
3
),
device
=
self
.
device
)
beta_sum
=
torch
.
zeros
((
total_num_vd
,
1
),
device
=
self
.
device
)
idx_group
=
torch
.
gather
(
input
=
idx_map
.
reshape
(
-
1
),
dim
=
0
,
index
=
edge_group_to_cube
*
12
+
edge_group
)
x_group
=
torch
.
index_select
(
input
=
surf_edges_x
,
index
=
idx_group
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
2
,
3
)
s_group
=
torch
.
index_select
(
input
=
surf_edges_s
,
index
=
idx_group
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
2
,
1
)
zero_crossing_group
=
torch
.
index_select
(
input
=
zero_crossing
,
index
=
idx_group
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
3
)
alpha_group
=
torch
.
index_select
(
input
=
alpha_nx12x2
.
reshape
(
-
1
,
2
),
dim
=
0
,
index
=
edge_group_to_cube
*
12
+
edge_group
).
reshape
(
-
1
,
2
,
1
)
ue_group
=
self
.
_linear_interp
(
s_group
*
alpha_group
,
x_group
)
beta_group
=
torch
.
gather
(
input
=
beta_fx12
.
reshape
(
-
1
),
dim
=
0
,
index
=
edge_group_to_cube
*
12
+
edge_group
).
reshape
(
-
1
,
1
)
beta_sum
=
beta_sum
.
index_add_
(
0
,
index
=
edge_group_to_vd
,
source
=
beta_group
)
vd
=
vd
.
index_add_
(
0
,
index
=
edge_group_to_vd
,
source
=
ue_group
*
beta_group
)
/
beta_sum
L_dev
=
self
.
_compute_reg_loss
(
vd
,
zero_crossing_group
,
edge_group_to_vd
,
vd_num_edges
)
v_idx
=
torch
.
arange
(
vd
.
shape
[
0
],
device
=
self
.
device
)
# + total_num_vd
vd_idx_map
=
(
vd_idx_map
.
reshape
(
-
1
)).
scatter
(
dim
=
0
,
index
=
edge_group_to_cube
*
12
+
edge_group
,
src
=
v_idx
[
edge_group_to_vd
])
return
vd
,
L_dev
,
vd_gamma
,
vd_idx_map
def
_triangulate
(
self
,
s_n
,
surf_edges
,
vd
,
vd_gamma
,
edge_counts
,
idx_map
,
vd_idx_map
,
surf_edges_mask
,
training
,
grad_func
):
"""
Connects four neighboring dual vertices to form a quadrilateral. The quadrilaterals are then split into
triangles based on the gamma parameter, as described in Section 4.3.
"""
with
torch
.
no_grad
():
group_mask
=
(
edge_counts
==
4
)
&
surf_edges_mask
# surface edges shared by 4 cubes.
group
=
idx_map
.
reshape
(
-
1
)[
group_mask
]
vd_idx
=
vd_idx_map
[
group_mask
]
edge_indices
,
indices
=
torch
.
sort
(
group
,
stable
=
True
)
quad_vd_idx
=
vd_idx
[
indices
].
reshape
(
-
1
,
4
)
# Ensure all face directions point towards the positive SDF to maintain consistent winding.
s_edges
=
s_n
[
surf_edges
[
edge_indices
.
reshape
(
-
1
,
4
)[:,
0
]].
reshape
(
-
1
)].
reshape
(
-
1
,
2
)
flip_mask
=
s_edges
[:,
0
]
>
0
quad_vd_idx
=
torch
.
cat
((
quad_vd_idx
[
flip_mask
][:,
[
0
,
1
,
3
,
2
]],
quad_vd_idx
[
~
flip_mask
][:,
[
2
,
3
,
1
,
0
]]))
if
grad_func
is
not
None
:
# when grad_func is given, split quadrilaterals along the diagonals with more consistent gradients.
with
torch
.
no_grad
():
vd_gamma
=
torch
.
nn
.
functional
.
normalize
(
grad_func
(
vd
),
dim
=-
1
)
quad_gamma
=
torch
.
index_select
(
input
=
vd_gamma
,
index
=
quad_vd_idx
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
4
,
3
)
gamma_02
=
(
quad_gamma
[:,
0
]
*
quad_gamma
[:,
2
]).
sum
(
-
1
,
keepdims
=
True
)
gamma_13
=
(
quad_gamma
[:,
1
]
*
quad_gamma
[:,
3
]).
sum
(
-
1
,
keepdims
=
True
)
else
:
quad_gamma
=
torch
.
index_select
(
input
=
vd_gamma
,
index
=
quad_vd_idx
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
4
)
gamma_02
=
torch
.
index_select
(
input
=
quad_gamma
,
index
=
torch
.
tensor
(
0
,
device
=
self
.
device
),
dim
=
1
)
*
torch
.
index_select
(
input
=
quad_gamma
,
index
=
torch
.
tensor
(
2
,
device
=
self
.
device
),
dim
=
1
)
gamma_13
=
torch
.
index_select
(
input
=
quad_gamma
,
index
=
torch
.
tensor
(
1
,
device
=
self
.
device
),
dim
=
1
)
*
torch
.
index_select
(
input
=
quad_gamma
,
index
=
torch
.
tensor
(
3
,
device
=
self
.
device
),
dim
=
1
)
if
not
training
:
mask
=
(
gamma_02
>
gamma_13
).
squeeze
(
1
)
faces
=
torch
.
zeros
((
quad_gamma
.
shape
[
0
],
6
),
dtype
=
torch
.
long
,
device
=
quad_vd_idx
.
device
)
faces
[
mask
]
=
quad_vd_idx
[
mask
][:,
self
.
quad_split_1
]
faces
[
~
mask
]
=
quad_vd_idx
[
~
mask
][:,
self
.
quad_split_2
]
faces
=
faces
.
reshape
(
-
1
,
3
)
else
:
vd_quad
=
torch
.
index_select
(
input
=
vd
,
index
=
quad_vd_idx
.
reshape
(
-
1
),
dim
=
0
).
reshape
(
-
1
,
4
,
3
)
vd_02
=
(
torch
.
index_select
(
input
=
vd_quad
,
index
=
torch
.
tensor
(
0
,
device
=
self
.
device
),
dim
=
1
)
+
torch
.
index_select
(
input
=
vd_quad
,
index
=
torch
.
tensor
(
2
,
device
=
self
.
device
),
dim
=
1
))
/
2
vd_13
=
(
torch
.
index_select
(
input
=
vd_quad
,
index
=
torch
.
tensor
(
1
,
device
=
self
.
device
),
dim
=
1
)
+
torch
.
index_select
(
input
=
vd_quad
,
index
=
torch
.
tensor
(
3
,
device
=
self
.
device
),
dim
=
1
))
/
2
weight_sum
=
(
gamma_02
+
gamma_13
)
+
1e-8
vd_center
=
((
vd_02
*
gamma_02
.
unsqueeze
(
-
1
)
+
vd_13
*
gamma_13
.
unsqueeze
(
-
1
))
/
weight_sum
.
unsqueeze
(
-
1
)).
squeeze
(
1
)
vd_center_idx
=
torch
.
arange
(
vd_center
.
shape
[
0
],
device
=
self
.
device
)
+
vd
.
shape
[
0
]
vd
=
torch
.
cat
([
vd
,
vd_center
])
faces
=
quad_vd_idx
[:,
self
.
quad_split_train
].
reshape
(
-
1
,
4
,
2
)
faces
=
torch
.
cat
([
faces
,
vd_center_idx
.
reshape
(
-
1
,
1
,
1
).
repeat
(
1
,
4
,
1
)],
-
1
).
reshape
(
-
1
,
3
)
return
vd
,
faces
,
s_edges
,
edge_indices
def
_tetrahedralize
(
self
,
x_nx3
,
s_n
,
cube_fx8
,
vertices
,
faces
,
surf_edges
,
s_edges
,
vd_idx_map
,
case_ids
,
edge_indices
,
surf_cubes
,
training
):
"""
Tetrahedralizes the interior volume to produce a tetrahedral mesh, as described in Section 4.5.
"""
occ_n
=
s_n
<
0
occ_fx8
=
occ_n
[
cube_fx8
.
reshape
(
-
1
)].
reshape
(
-
1
,
8
)
occ_sum
=
torch
.
sum
(
occ_fx8
,
-
1
)
inside_verts
=
x_nx3
[
occ_n
]
mapping_inside_verts
=
torch
.
ones
((
occ_n
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
self
.
device
)
*
-
1
mapping_inside_verts
[
occ_n
]
=
torch
.
arange
(
occ_n
.
sum
(),
device
=
self
.
device
)
+
vertices
.
shape
[
0
]
"""
For each grid edge connecting two grid vertices with different
signs, we first form a four-sided pyramid by connecting one
of the grid vertices with four mesh vertices that correspond
to the grid edge and then subdivide the pyramid into two tetrahedra
"""
inside_verts_idx
=
mapping_inside_verts
[
surf_edges
[
edge_indices
.
reshape
(
-
1
,
4
)[:,
0
]].
reshape
(
-
1
,
2
)[
s_edges
<
0
]]
if
not
training
:
inside_verts_idx
=
inside_verts_idx
.
unsqueeze
(
1
).
expand
(
-
1
,
2
).
reshape
(
-
1
)
else
:
inside_verts_idx
=
inside_verts_idx
.
unsqueeze
(
1
).
expand
(
-
1
,
4
).
reshape
(
-
1
)
tets_surface
=
torch
.
cat
([
faces
,
inside_verts_idx
.
unsqueeze
(
-
1
)],
-
1
)
"""
For each grid edge connecting two grid vertices with the
same sign, the tetrahedron is formed by the two grid vertices
and two vertices in consecutive adjacent cells
"""
inside_cubes
=
(
occ_sum
==
8
)
inside_cubes_center
=
x_nx3
[
cube_fx8
[
inside_cubes
].
reshape
(
-
1
)].
reshape
(
-
1
,
8
,
3
).
mean
(
1
)
inside_cubes_center_idx
=
torch
.
arange
(
inside_cubes_center
.
shape
[
0
],
device
=
inside_cubes
.
device
)
+
vertices
.
shape
[
0
]
+
inside_verts
.
shape
[
0
]
surface_n_inside_cubes
=
surf_cubes
|
inside_cubes
edge_center_vertex_idx
=
torch
.
ones
(((
surface_n_inside_cubes
).
sum
(),
13
),
dtype
=
torch
.
long
,
device
=
x_nx3
.
device
)
*
-
1
surf_cubes
=
surf_cubes
[
surface_n_inside_cubes
]
inside_cubes
=
inside_cubes
[
surface_n_inside_cubes
]
edge_center_vertex_idx
[
surf_cubes
,
:
12
]
=
vd_idx_map
.
reshape
(
-
1
,
12
)
edge_center_vertex_idx
[
inside_cubes
,
12
]
=
inside_cubes_center_idx
all_edges
=
cube_fx8
[
surface_n_inside_cubes
][:,
self
.
cube_edges
].
reshape
(
-
1
,
2
)
unique_edges
,
_idx_map
,
counts
=
torch
.
unique
(
all_edges
,
dim
=
0
,
return_inverse
=
True
,
return_counts
=
True
)
unique_edges
=
unique_edges
.
long
()
mask_edges
=
occ_n
[
unique_edges
.
reshape
(
-
1
)].
reshape
(
-
1
,
2
).
sum
(
-
1
)
==
2
mask
=
mask_edges
[
_idx_map
]
counts
=
counts
[
_idx_map
]
mapping
=
torch
.
ones
((
unique_edges
.
shape
[
0
]),
dtype
=
torch
.
long
,
device
=
self
.
device
)
*
-
1
mapping
[
mask_edges
]
=
torch
.
arange
(
mask_edges
.
sum
(),
device
=
self
.
device
)
idx_map
=
mapping
[
_idx_map
]
group_mask
=
(
counts
==
4
)
&
mask
group
=
idx_map
.
reshape
(
-
1
)[
group_mask
]
edge_indices
,
indices
=
torch
.
sort
(
group
)
cube_idx
=
torch
.
arange
((
_idx_map
.
shape
[
0
]
//
12
),
dtype
=
torch
.
long
,
device
=
self
.
device
).
unsqueeze
(
1
).
expand
(
-
1
,
12
).
reshape
(
-
1
)[
group_mask
]
edge_idx
=
torch
.
arange
((
12
),
dtype
=
torch
.
long
,
device
=
self
.
device
).
unsqueeze
(
0
).
expand
(
_idx_map
.
shape
[
0
]
//
12
,
-
1
).
reshape
(
-
1
)[
group_mask
]
# Identify the face shared by the adjacent cells.
cube_idx_4
=
cube_idx
[
indices
].
reshape
(
-
1
,
4
)
edge_dir
=
self
.
edge_dir_table
[
edge_idx
[
indices
]].
reshape
(
-
1
,
4
)[...,
0
]
shared_faces_4x2
=
self
.
dir_faces_table
[
edge_dir
].
reshape
(
-
1
)
cube_idx_4x2
=
cube_idx_4
[:,
self
.
adj_pairs
].
reshape
(
-
1
)
# Identify an edge of the face with different signs and
# select the mesh vertex corresponding to the identified edge.
case_ids_expand
=
torch
.
ones
((
surface_n_inside_cubes
).
sum
(),
dtype
=
torch
.
long
,
device
=
x_nx3
.
device
)
*
255
case_ids_expand
[
surf_cubes
]
=
case_ids
cases
=
case_ids_expand
[
cube_idx_4x2
]
quad_edge
=
edge_center_vertex_idx
[
cube_idx_4x2
,
self
.
tet_table
[
cases
,
shared_faces_4x2
]].
reshape
(
-
1
,
2
)
mask
=
(
quad_edge
==
-
1
).
sum
(
-
1
)
==
0
inside_edge
=
mapping_inside_verts
[
unique_edges
[
mask_edges
][
edge_indices
].
reshape
(
-
1
)].
reshape
(
-
1
,
2
)
tets_inside
=
torch
.
cat
([
quad_edge
,
inside_edge
],
-
1
)[
mask
]
tets
=
torch
.
cat
([
tets_surface
,
tets_inside
])
vertices
=
torch
.
cat
([
vertices
,
inside_verts
,
inside_cubes_center
])
return
vertices
,
tets
InstantMesh/src/models/geometry/rep_3d/flexicubes_geometry.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
import
torch
import
numpy
as
np
import
os
from
.
import
Geometry
from
.flexicubes
import
FlexiCubes
# replace later
from
.dmtet
import
sdf_reg_loss_batch
import
torch.nn.functional
as
F
def
get_center_boundary_index
(
grid_res
,
device
):
v
=
torch
.
zeros
((
grid_res
+
1
,
grid_res
+
1
,
grid_res
+
1
),
dtype
=
torch
.
bool
,
device
=
device
)
v
[
grid_res
//
2
+
1
,
grid_res
//
2
+
1
,
grid_res
//
2
+
1
]
=
True
center_indices
=
torch
.
nonzero
(
v
.
reshape
(
-
1
))
v
[
grid_res
//
2
+
1
,
grid_res
//
2
+
1
,
grid_res
//
2
+
1
]
=
False
v
[:
2
,
...]
=
True
v
[
-
2
:,
...]
=
True
v
[:,
:
2
,
...]
=
True
v
[:,
-
2
:,
...]
=
True
v
[:,
:,
:
2
]
=
True
v
[:,
:,
-
2
:]
=
True
boundary_indices
=
torch
.
nonzero
(
v
.
reshape
(
-
1
))
return
center_indices
,
boundary_indices
###############################################################################
# Geometry interface
###############################################################################
class
FlexiCubesGeometry
(
Geometry
):
def
__init__
(
self
,
grid_res
=
64
,
scale
=
2.0
,
device
=
'cuda'
,
renderer
=
None
,
render_type
=
'neural_render'
,
args
=
None
):
super
(
FlexiCubesGeometry
,
self
).
__init__
()
self
.
grid_res
=
grid_res
self
.
device
=
device
self
.
args
=
args
self
.
fc
=
FlexiCubes
(
device
,
weight_scale
=
0.5
)
self
.
verts
,
self
.
indices
=
self
.
fc
.
construct_voxel_grid
(
grid_res
)
if
isinstance
(
scale
,
list
):
self
.
verts
[:,
0
]
=
self
.
verts
[:,
0
]
*
scale
[
0
]
self
.
verts
[:,
1
]
=
self
.
verts
[:,
1
]
*
scale
[
1
]
self
.
verts
[:,
2
]
=
self
.
verts
[:,
2
]
*
scale
[
1
]
else
:
self
.
verts
=
self
.
verts
*
scale
all_edges
=
self
.
indices
[:,
self
.
fc
.
cube_edges
].
reshape
(
-
1
,
2
)
self
.
all_edges
=
torch
.
unique
(
all_edges
,
dim
=
0
)
# Parameters used for fix boundary sdf
self
.
center_indices
,
self
.
boundary_indices
=
get_center_boundary_index
(
self
.
grid_res
,
device
)
self
.
renderer
=
renderer
self
.
render_type
=
render_type
def
getAABB
(
self
):
return
torch
.
min
(
self
.
verts
,
dim
=
0
).
values
,
torch
.
max
(
self
.
verts
,
dim
=
0
).
values
def
get_mesh
(
self
,
v_deformed_nx3
,
sdf_n
,
weight_n
=
None
,
with_uv
=
False
,
indices
=
None
,
is_training
=
False
):
if
indices
is
None
:
indices
=
self
.
indices
verts
,
faces
,
v_reg_loss
=
self
.
fc
(
v_deformed_nx3
,
sdf_n
,
indices
,
self
.
grid_res
,
beta_fx12
=
weight_n
[:,
:
12
],
alpha_fx8
=
weight_n
[:,
12
:
20
],
gamma_f
=
weight_n
[:,
20
],
training
=
is_training
)
return
verts
,
faces
,
v_reg_loss
def
render_mesh
(
self
,
mesh_v_nx3
,
mesh_f_fx3
,
camera_mv_bx4x4
,
resolution
=
256
,
hierarchical_mask
=
False
):
return_value
=
dict
()
if
self
.
render_type
==
'neural_render'
:
tex_pos
,
mask
,
hard_mask
,
rast
,
v_pos_clip
,
mask_pyramid
,
depth
,
normal
=
self
.
renderer
.
render_mesh
(
mesh_v_nx3
.
unsqueeze
(
dim
=
0
),
mesh_f_fx3
.
int
(),
camera_mv_bx4x4
,
mesh_v_nx3
.
unsqueeze
(
dim
=
0
),
resolution
=
resolution
,
device
=
self
.
device
,
hierarchical_mask
=
hierarchical_mask
)
return_value
[
'tex_pos'
]
=
tex_pos
return_value
[
'mask'
]
=
mask
return_value
[
'hard_mask'
]
=
hard_mask
return_value
[
'rast'
]
=
rast
return_value
[
'v_pos_clip'
]
=
v_pos_clip
return_value
[
'mask_pyramid'
]
=
mask_pyramid
return_value
[
'depth'
]
=
depth
return_value
[
'normal'
]
=
normal
else
:
raise
NotImplementedError
return
return_value
def
render
(
self
,
v_deformed_bxnx3
=
None
,
sdf_bxn
=
None
,
camera_mv_bxnviewx4x4
=
None
,
resolution
=
256
):
# Here I assume a batch of meshes (can be different mesh and geometry), for the other shapes, the batch is 1
v_list
=
[]
f_list
=
[]
n_batch
=
v_deformed_bxnx3
.
shape
[
0
]
all_render_output
=
[]
for
i_batch
in
range
(
n_batch
):
verts_nx3
,
faces_fx3
=
self
.
get_mesh
(
v_deformed_bxnx3
[
i_batch
],
sdf_bxn
[
i_batch
])
v_list
.
append
(
verts_nx3
)
f_list
.
append
(
faces_fx3
)
render_output
=
self
.
render_mesh
(
verts_nx3
,
faces_fx3
,
camera_mv_bxnviewx4x4
[
i_batch
],
resolution
)
all_render_output
.
append
(
render_output
)
# Concatenate all render output
return_keys
=
all_render_output
[
0
].
keys
()
return_value
=
dict
()
for
k
in
return_keys
:
value
=
[
v
[
k
]
for
v
in
all_render_output
]
return_value
[
k
]
=
value
# We can do concatenation outside of the render
return
return_value
InstantMesh/src/models/geometry/rep_3d/tables.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# NVIDIA CORPORATION & AFFILIATES and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION & AFFILIATES is strictly prohibited.
dmc_table
=
[
[[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
7
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
5
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
7
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
7
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
5
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
8
,
9
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
7
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
5
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
7
,
8
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
5
,
7
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
8
,
9
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
7
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
7
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
5
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
5
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
7
,
9
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
7
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
8
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
9
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
8
,
9
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
3
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
7
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
9
,
10
,
11
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
9
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
3
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
8
,
10
,
11
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
5
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
8
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
1
,
3
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
7
,
9
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
7
,
8
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
6
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
6
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
6
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
5
,
8
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
6
,
8
,
9
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
6
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
6
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
5
,
6
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
6
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
6
,
7
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
6
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
6
,
7
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
6
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
4
,
6
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
6
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
6
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
6
,
7
,
8
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
6
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
5
,
6
,
7
,
8
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
6
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
6
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
5
,
6
,
8
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
5
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
8
,
9
,
10
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
6
,
11
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
4
,
6
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
6
,
9
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
5
,
10
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
5
,
8
,
10
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
6
,
8
,
9
,
11
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
6
,
9
,
11
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
6
,
8
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
6
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
6
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
6
,
7
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
6
,
7
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
6
,
7
,
8
,
9
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
6
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
6
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
6
,
8
,
9
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
3
,
6
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
6
,
7
,
8
,
10
,
-
1
],
[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
5
,
6
,
7
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
6
,
7
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
5
,
6
,
8
,
9
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
6
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
7
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
7
,
9
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
6
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
6
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
6
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
6
,
7
,
8
,
9
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
6
,
7
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
6
,
7
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
6
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
8
,
9
,
11
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
7
,
11
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
7
,
9
,
11
,
-
1
],
[
5
,
6
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
4
,
6
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
6
,
10
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
6
,
8
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
6
,
7
,
8
,
9
,
10
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
6
,
7
,
9
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
6
,
7
,
8
,
10
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
6
,
7
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
5
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
5
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
6
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
6
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
5
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
7
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
5
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
6
,
9
,
-
1
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
5
,
6
,
7
,
9
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
6
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
4
,
6
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
6
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
6
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
6
,
7
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
6
,
7
,
9
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
6
,
7
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
6
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
5
,
6
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
6
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
6
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
6
,
8
,
9
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
3
,
5
,
6
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
6
,
7
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
6
,
9
,
11
,
-
1
],
[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
6
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
6
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
6
,
8
,
9
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
6
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
6
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
6
,
7
,
8
,
9
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
6
,
7
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
6
,
7
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
7
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
5
,
7
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
5
,
7
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
8
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
5
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
5
,
8
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
5
,
9
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
9
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
4
,
7
,
9
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
7
,
10
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
7
,
8
,
10
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
8
,
9
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
9
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
8
,
10
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
10
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
7
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
5
,
7
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
5
,
7
,
8
,
9
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
5
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
5
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
4
,
5
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
5
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
7
,
9
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
7
,
8
,
9
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
4
,
7
,
10
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
8
,
9
,
10
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
9
,
10
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
8
,
10
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
10
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
5
,
7
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
5
,
7
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
5
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
5
,
7
,
8
,
9
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
5
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
4
,
5
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
5
,
8
,
9
,
11
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
4
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
1
,
2
,
4
,
7
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
4
,
7
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
4
,
7
,
8
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
2
,
8
,
9
,
11
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
2
,
3
,
9
,
11
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
2
,
8
,
11
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
2
,
3
,
11
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
5
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
5
,
7
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
5
,
7
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
5
,
7
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
5
,
8
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
5
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
5
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
5
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
4
,
7
,
9
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
4
,
7
,
8
,
9
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
4
,
7
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
4
,
7
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
1
,
3
,
8
,
9
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
1
,
9
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
0
,
3
,
8
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]],
[[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
]]
]
num_vd_table
=
[
0
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
2
,
1
,
3
,
1
,
2
,
2
,
2
,
1
,
2
,
1
,
2
,
1
,
1
,
2
,
1
,
1
,
2
,
2
,
2
,
1
,
2
,
3
,
1
,
1
,
2
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
2
,
1
,
2
,
2
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
2
,
2
,
2
,
1
,
1
,
2
,
1
,
2
,
3
,
2
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
2
,
1
,
2
,
2
,
2
,
1
,
1
,
1
,
1
,
1
,
2
,
3
,
2
,
2
,
2
,
2
,
2
,
1
,
3
,
4
,
2
,
2
,
2
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
2
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
2
,
2
,
2
,
2
,
2
,
3
,
2
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
2
,
3
,
2
,
3
,
2
,
4
,
2
,
2
,
2
,
2
,
1
,
2
,
1
,
2
,
1
,
1
,
2
,
1
,
1
,
2
,
2
,
2
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
2
,
2
,
2
,
1
,
1
,
2
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
2
,
1
,
2
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
]
check_table
=
[
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
0
,
0
,
194
],
[
1
,
-
1
,
0
,
0
,
193
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
1
,
0
,
164
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
-
1
,
0
,
161
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
1
,
152
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
1
,
145
],
[
1
,
0
,
0
,
1
,
144
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
-
1
,
137
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
1
,
0
,
133
],
[
1
,
0
,
1
,
0
,
132
],
[
1
,
1
,
0
,
0
,
131
],
[
1
,
1
,
0
,
0
,
130
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
1
,
100
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
1
,
98
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
1
,
96
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
1
,
0
,
88
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
-
1
,
0
,
82
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
1
,
0
,
74
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
1
,
0
,
72
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
-
1
,
70
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
-
1
,
0
,
0
,
67
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
-
1
,
0
,
0
,
65
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
0
,
0
,
56
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
-
1
,
0
,
0
,
52
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
0
,
0
,
44
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
0
,
0
,
40
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
-
1
,
38
],
[
1
,
0
,
-
1
,
0
,
37
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
-
1
,
0
,
33
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
-
1
,
0
,
0
,
28
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
-
1
,
0
,
26
],
[
1
,
0
,
0
,
-
1
,
25
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
-
1
,
0
,
0
,
20
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
-
1
,
0
,
18
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
-
1
,
9
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
1
,
0
,
0
,
-
1
,
6
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
]
]
tet_table
=
[
[
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
0
,
0
,
4
,
4
,
-
1
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
0
,
4
,
0
,
4
,
4
,
-
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
-
1
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
-
1
,
2
,
4
,
4
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
4
,
4
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
4
,
2
,
4
,
4
,
2
],
[
0
,
4
,
0
,
4
,
4
,
0
],
[
2
,
0
,
2
,
0
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
5
,
2
,
5
,
5
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
0
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
1
,
1
,
-
1
,
0
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
4
,
1
,
1
,
4
,
4
,
1
],
[
0
,
1
,
1
,
0
,
0
,
1
],
[
4
,
0
,
0
,
4
,
4
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
-
1
,
1
,
1
,
4
,
4
,
1
],
[
0
,
1
,
1
,
4
,
4
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
5
,
1
,
1
,
5
,
5
,
1
],
[
0
,
1
,
1
,
0
,
0
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
8
,
8
,
8
,
8
,
8
,
8
],
[
1
,
1
,
1
,
4
,
4
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
0
,
0
,
4
,
4
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
4
,
4
,
1
],
[
0
,
4
,
0
,
4
,
4
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
5
,
5
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
6
,
6
,
6
,
6
,
6
,
6
],
[
6
,
-
1
,
0
,
6
,
0
,
6
],
[
6
,
0
,
0
,
6
,
0
,
6
],
[
6
,
1
,
1
,
6
,
1
,
6
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
0
,
0
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
6
,
4
,
-
1
,
6
,
4
,
6
],
[
6
,
4
,
0
,
6
,
4
,
6
],
[
6
,
0
,
0
,
6
,
0
,
6
],
[
6
,
1
,
1
,
6
,
1
,
6
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
2
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
4
,
2
,
2
,
4
,
2
],
[
0
,
4
,
0
,
4
,
4
,
0
],
[
2
,
0
,
2
,
2
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
6
,
1
,
1
,
6
,
-
1
,
6
],
[
6
,
1
,
1
,
6
,
0
,
6
],
[
6
,
0
,
0
,
6
,
0
,
6
],
[
6
,
2
,
2
,
6
,
2
,
6
],
[
4
,
1
,
1
,
4
,
4
,
1
],
[
0
,
1
,
1
,
0
,
0
,
1
],
[
4
,
0
,
0
,
4
,
4
,
4
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
6
,
1
,
1
,
6
,
4
,
6
],
[
6
,
1
,
1
,
6
,
4
,
6
],
[
6
,
0
,
0
,
6
,
0
,
6
],
[
6
,
2
,
2
,
6
,
2
,
6
],
[
5
,
1
,
1
,
5
,
5
,
1
],
[
0
,
1
,
1
,
0
,
0
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
6
,
6
,
6
,
6
,
6
,
6
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
4
,
1
],
[
0
,
4
,
0
,
4
,
4
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
5
,
0
,
5
,
0
,
5
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
0
,
5
,
0
,
5
,
0
,
5
],
[
-
1
,
5
,
0
,
5
,
0
,
5
],
[
1
,
5
,
1
,
5
,
1
,
5
],
[
4
,
5
,
-
1
,
5
,
4
,
5
],
[
0
,
5
,
0
,
5
,
0
,
5
],
[
4
,
5
,
0
,
5
,
4
,
5
],
[
1
,
5
,
1
,
5
,
1
,
5
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
0
,
4
,
0
,
4
,
4
,
4
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
6
,
6
,
6
,
6
,
6
,
6
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
5
,
2
,
5
,
-
1
,
5
],
[
0
,
5
,
0
,
5
,
0
,
5
],
[
2
,
5
,
2
,
5
,
0
,
5
],
[
1
,
5
,
1
,
5
,
1
,
5
],
[
2
,
5
,
2
,
5
,
4
,
5
],
[
0
,
5
,
0
,
5
,
0
,
5
],
[
2
,
5
,
2
,
5
,
4
,
5
],
[
1
,
5
,
1
,
5
,
1
,
5
],
[
2
,
4
,
2
,
4
,
4
,
2
],
[
0
,
4
,
0
,
4
,
4
,
4
],
[
2
,
0
,
2
,
0
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
6
,
2
,
6
,
6
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
0
,
2
,
0
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
1
,
1
,
1
,
0
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
4
,
1
,
1
,
1
,
4
,
1
],
[
0
,
1
,
1
,
1
,
0
,
1
],
[
4
,
0
,
0
,
4
,
4
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
1
,
1
,
1
,
1
,
4
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
0
,
0
,
4
,
4
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
6
,
0
,
0
,
6
,
0
,
6
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
6
,
6
,
6
,
6
,
6
,
6
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
5
,
5
,
0
,
5
,
0
,
5
],
[
5
,
5
,
0
,
5
,
0
,
5
],
[
5
,
5
,
1
,
5
,
1
,
5
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
0
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
4
,
4
,
0
,
4
,
4
,
4
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
8
,
8
,
8
,
8
,
8
,
8
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
0
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
1
,
1
,
4
,
4
,
1
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
1
,
1
,
1
,
1
,
0
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
4
,
2
,
4
,
4
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
2
,
2
,
2
,
2
,
2
,
2
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
5
,
5
,
5
,
5
,
5
,
5
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
4
,
4
,
4
,
4
,
4
,
4
],
[
1
,
1
,
1
,
1
,
1
,
1
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
,
0
,
0
],
[
12
,
12
,
12
,
12
,
12
,
12
]
]
InstantMesh/src/models/lrm.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2023, Zexin He
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import
numpy
as
np
import
torch
import
torch.nn
as
nn
import
mcubes
import
nvdiffrast.torch
as
dr
from
einops
import
rearrange
,
repeat
from
.encoder.dino_wrapper
import
DinoWrapper
from
.decoder.transformer
import
TriplaneTransformer
from
.renderer.synthesizer
import
TriplaneSynthesizer
from
..utils.mesh_util
import
xatlas_uvmap
class
InstantNeRF
(
nn
.
Module
):
"""
Full model of the large reconstruction model.
"""
def
__init__
(
self
,
encoder_freeze
:
bool
=
False
,
encoder_model_name
:
str
=
'facebook/dino-vitb16'
,
encoder_feat_dim
:
int
=
768
,
transformer_dim
:
int
=
1024
,
transformer_layers
:
int
=
16
,
transformer_heads
:
int
=
16
,
triplane_low_res
:
int
=
32
,
triplane_high_res
:
int
=
64
,
triplane_dim
:
int
=
80
,
rendering_samples_per_ray
:
int
=
128
,
):
super
().
__init__
()
# modules
self
.
encoder
=
DinoWrapper
(
model_name
=
encoder_model_name
,
freeze
=
encoder_freeze
,
)
self
.
transformer
=
TriplaneTransformer
(
inner_dim
=
transformer_dim
,
num_layers
=
transformer_layers
,
num_heads
=
transformer_heads
,
image_feat_dim
=
encoder_feat_dim
,
triplane_low_res
=
triplane_low_res
,
triplane_high_res
=
triplane_high_res
,
triplane_dim
=
triplane_dim
,
)
self
.
synthesizer
=
TriplaneSynthesizer
(
triplane_dim
=
triplane_dim
,
samples_per_ray
=
rendering_samples_per_ray
,
)
def
forward_planes
(
self
,
images
,
cameras
):
# images: [B, V, C_img, H_img, W_img]
# cameras: [B, V, 16]
B
=
images
.
shape
[
0
]
# encode images
image_feats
=
self
.
encoder
(
images
,
cameras
)
image_feats
=
rearrange
(
image_feats
,
'(b v) l d -> b (v l) d'
,
b
=
B
)
# transformer generating planes
planes
=
self
.
transformer
(
image_feats
)
return
planes
def
forward_synthesizer
(
self
,
planes
,
render_cameras
,
render_size
:
int
):
render_results
=
self
.
synthesizer
(
planes
,
render_cameras
,
render_size
,
)
return
render_results
def
forward
(
self
,
images
,
cameras
,
render_cameras
,
render_size
:
int
):
# images: [B, V, C_img, H_img, W_img]
# cameras: [B, V, 16]
# render_cameras: [B, M, D_cam_render]
# render_size: int
B
,
M
=
render_cameras
.
shape
[:
2
]
planes
=
self
.
forward_planes
(
images
,
cameras
)
# render target views
render_results
=
self
.
synthesizer
(
planes
,
render_cameras
,
render_size
)
return
{
'planes'
:
planes
,
**
render_results
,
}
def
get_texture_prediction
(
self
,
planes
,
tex_pos
,
hard_mask
=
None
):
'''
Predict Texture given triplanes
:param planes: the triplane feature map
:param tex_pos: Position we want to query the texture field
:param hard_mask: 2D silhoueete of the rendered image
'''
tex_pos
=
torch
.
cat
(
tex_pos
,
dim
=
0
)
if
not
hard_mask
is
None
:
tex_pos
=
tex_pos
*
hard_mask
.
float
()
batch_size
=
tex_pos
.
shape
[
0
]
tex_pos
=
tex_pos
.
reshape
(
batch_size
,
-
1
,
3
)
###################
# We use mask to get the texture location (to save the memory)
if
hard_mask
is
not
None
:
n_point_list
=
torch
.
sum
(
hard_mask
.
long
().
reshape
(
hard_mask
.
shape
[
0
],
-
1
),
dim
=-
1
)
sample_tex_pose_list
=
[]
max_point
=
n_point_list
.
max
()
expanded_hard_mask
=
hard_mask
.
reshape
(
batch_size
,
-
1
,
1
).
expand
(
-
1
,
-
1
,
3
)
>
0.5
for
i
in
range
(
tex_pos
.
shape
[
0
]):
tex_pos_one_shape
=
tex_pos
[
i
][
expanded_hard_mask
[
i
]].
reshape
(
1
,
-
1
,
3
)
if
tex_pos_one_shape
.
shape
[
1
]
<
max_point
:
tex_pos_one_shape
=
torch
.
cat
(
[
tex_pos_one_shape
,
torch
.
zeros
(
1
,
max_point
-
tex_pos_one_shape
.
shape
[
1
],
3
,
device
=
tex_pos_one_shape
.
device
,
dtype
=
torch
.
float32
)],
dim
=
1
)
sample_tex_pose_list
.
append
(
tex_pos_one_shape
)
tex_pos
=
torch
.
cat
(
sample_tex_pose_list
,
dim
=
0
)
tex_feat
=
torch
.
utils
.
checkpoint
.
checkpoint
(
self
.
synthesizer
.
forward_points
,
planes
,
tex_pos
,
use_reentrant
=
False
,
)[
'rgb'
]
if
hard_mask
is
not
None
:
final_tex_feat
=
torch
.
zeros
(
planes
.
shape
[
0
],
hard_mask
.
shape
[
1
]
*
hard_mask
.
shape
[
2
],
tex_feat
.
shape
[
-
1
],
device
=
tex_feat
.
device
)
expanded_hard_mask
=
hard_mask
.
reshape
(
hard_mask
.
shape
[
0
],
-
1
,
1
).
expand
(
-
1
,
-
1
,
final_tex_feat
.
shape
[
-
1
])
>
0.5
for
i
in
range
(
planes
.
shape
[
0
]):
final_tex_feat
[
i
][
expanded_hard_mask
[
i
]]
=
tex_feat
[
i
][:
n_point_list
[
i
]].
reshape
(
-
1
)
tex_feat
=
final_tex_feat
return
tex_feat
.
reshape
(
planes
.
shape
[
0
],
hard_mask
.
shape
[
1
],
hard_mask
.
shape
[
2
],
tex_feat
.
shape
[
-
1
])
def
extract_mesh
(
self
,
planes
:
torch
.
Tensor
,
mesh_resolution
:
int
=
256
,
mesh_threshold
:
int
=
10.0
,
use_texture_map
:
bool
=
False
,
texture_resolution
:
int
=
1024
,
**
kwargs
,
):
'''
Extract a 3D mesh from triplane nerf. Only support batch_size 1.
:param planes: triplane features
:param mesh_resolution: marching cubes resolution
:param mesh_threshold: iso-surface threshold
:param use_texture_map: use texture map or vertex color
:param texture_resolution: the resolution of texture map
'''
assert
planes
.
shape
[
0
]
==
1
device
=
planes
.
device
grid_out
=
self
.
synthesizer
.
forward_grid
(
planes
=
planes
,
grid_size
=
mesh_resolution
,
)
vertices
,
faces
=
mcubes
.
marching_cubes
(
grid_out
[
'sigma'
].
squeeze
(
0
).
squeeze
(
-
1
).
cpu
().
numpy
(),
mesh_threshold
,
)
vertices
=
vertices
/
(
mesh_resolution
-
1
)
*
2
-
1
if
not
use_texture_map
:
# query vertex colors
vertices_tensor
=
torch
.
tensor
(
vertices
,
dtype
=
torch
.
float32
,
device
=
device
).
unsqueeze
(
0
)
vertices_colors
=
self
.
synthesizer
.
forward_points
(
planes
,
vertices_tensor
)[
'rgb'
].
squeeze
(
0
).
cpu
().
numpy
()
vertices_colors
=
(
vertices_colors
*
255
).
astype
(
np
.
uint8
)
return
vertices
,
faces
,
vertices_colors
# use x-atlas to get uv mapping for the mesh
vertices
=
torch
.
tensor
(
vertices
,
dtype
=
torch
.
float32
,
device
=
device
)
faces
=
torch
.
tensor
(
faces
.
astype
(
int
),
dtype
=
torch
.
long
,
device
=
device
)
ctx
=
dr
.
RasterizeCudaContext
(
device
=
device
)
uvs
,
mesh_tex_idx
,
gb_pos
,
tex_hard_mask
=
xatlas_uvmap
(
ctx
,
vertices
,
faces
,
resolution
=
texture_resolution
)
tex_hard_mask
=
tex_hard_mask
.
float
()
# query the texture field to get the RGB color for texture map
tex_feat
=
self
.
get_texture_prediction
(
planes
,
[
gb_pos
],
tex_hard_mask
)
background_feature
=
torch
.
zeros_like
(
tex_feat
)
img_feat
=
torch
.
lerp
(
background_feature
,
tex_feat
,
tex_hard_mask
)
texture_map
=
img_feat
.
permute
(
0
,
3
,
1
,
2
).
squeeze
(
0
)
return
vertices
,
faces
,
uvs
,
mesh_tex_idx
,
texture_map
\ No newline at end of file
InstantMesh/src/models/lrm_mesh.py
0 → 100644
View file @
63bde97a
# Copyright (c) 2023, Tencent Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import
numpy
as
np
import
torch
import
torch.nn
as
nn
import
nvdiffrast.torch
as
dr
from
einops
import
rearrange
,
repeat
from
.encoder.dino_wrapper
import
DinoWrapper
from
.decoder.transformer
import
TriplaneTransformer
from
.renderer.synthesizer_mesh
import
TriplaneSynthesizer
from
.geometry.camera.perspective_camera
import
PerspectiveCamera
from
.geometry.render.neural_render
import
NeuralRender
from
.geometry.rep_3d.flexicubes_geometry
import
FlexiCubesGeometry
from
..utils.mesh_util
import
xatlas_uvmap
class
InstantMesh
(
nn
.
Module
):
"""
Full model of the large reconstruction model.
"""
def
__init__
(
self
,
encoder_freeze
:
bool
=
False
,
encoder_model_name
:
str
=
'facebook/dino-vitb16'
,
encoder_feat_dim
:
int
=
768
,
transformer_dim
:
int
=
1024
,
transformer_layers
:
int
=
16
,
transformer_heads
:
int
=
16
,
triplane_low_res
:
int
=
32
,
triplane_high_res
:
int
=
64
,
triplane_dim
:
int
=
80
,
rendering_samples_per_ray
:
int
=
128
,
grid_res
:
int
=
128
,
grid_scale
:
float
=
2.0
,
):
super
().
__init__
()
# attributes
self
.
grid_res
=
grid_res
self
.
grid_scale
=
grid_scale
self
.
deformation_multiplier
=
4.0
# modules
self
.
encoder
=
DinoWrapper
(
model_name
=
encoder_model_name
,
freeze
=
encoder_freeze
,
)
self
.
transformer
=
TriplaneTransformer
(
inner_dim
=
transformer_dim
,
num_layers
=
transformer_layers
,
num_heads
=
transformer_heads
,
image_feat_dim
=
encoder_feat_dim
,
triplane_low_res
=
triplane_low_res
,
triplane_high_res
=
triplane_high_res
,
triplane_dim
=
triplane_dim
,
)
self
.
synthesizer
=
TriplaneSynthesizer
(
triplane_dim
=
triplane_dim
,
samples_per_ray
=
rendering_samples_per_ray
,
)
def
init_flexicubes_geometry
(
self
,
device
,
fovy
=
50.0
):
camera
=
PerspectiveCamera
(
fovy
=
fovy
,
device
=
device
)
renderer
=
NeuralRender
(
device
,
camera_model
=
camera
)
self
.
geometry
=
FlexiCubesGeometry
(
grid_res
=
self
.
grid_res
,
scale
=
self
.
grid_scale
,
renderer
=
renderer
,
render_type
=
'neural_render'
,
device
=
device
,
)
def
forward_planes
(
self
,
images
,
cameras
):
# images: [B, V, C_img, H_img, W_img]
# cameras: [B, V, 16]
B
=
images
.
shape
[
0
]
# encode images
image_feats
=
self
.
encoder
(
images
,
cameras
)
image_feats
=
rearrange
(
image_feats
,
'(b v) l d -> b (v l) d'
,
b
=
B
)
# decode triplanes
planes
=
self
.
transformer
(
image_feats
)
return
planes
def
get_sdf_deformation_prediction
(
self
,
planes
):
'''
Predict SDF and deformation for tetrahedron vertices
:param planes: triplane feature map for the geometry
'''
init_position
=
self
.
geometry
.
verts
.
unsqueeze
(
0
).
expand
(
planes
.
shape
[
0
],
-
1
,
-
1
)
# Step 1: predict the SDF and deformation
sdf
,
deformation
,
weight
=
torch
.
utils
.
checkpoint
.
checkpoint
(
self
.
synthesizer
.
get_geometry_prediction
,
planes
,
init_position
,
self
.
geometry
.
indices
,
use_reentrant
=
False
,
)
# Step 2: Normalize the deformation to avoid the flipped triangles.
deformation
=
1.0
/
(
self
.
grid_res
*
self
.
deformation_multiplier
)
*
torch
.
tanh
(
deformation
)
sdf_reg_loss
=
torch
.
zeros
(
sdf
.
shape
[
0
],
device
=
sdf
.
device
,
dtype
=
torch
.
float32
)
####
# Step 3: Fix some sdf if we observe empty shape (full positive or full negative)
sdf_bxnxnxn
=
sdf
.
reshape
((
sdf
.
shape
[
0
],
self
.
grid_res
+
1
,
self
.
grid_res
+
1
,
self
.
grid_res
+
1
))
sdf_less_boundary
=
sdf_bxnxnxn
[:,
1
:
-
1
,
1
:
-
1
,
1
:
-
1
].
reshape
(
sdf
.
shape
[
0
],
-
1
)
pos_shape
=
torch
.
sum
((
sdf_less_boundary
>
0
).
int
(),
dim
=-
1
)
neg_shape
=
torch
.
sum
((
sdf_less_boundary
<
0
).
int
(),
dim
=-
1
)
zero_surface
=
torch
.
bitwise_or
(
pos_shape
==
0
,
neg_shape
==
0
)
if
torch
.
sum
(
zero_surface
).
item
()
>
0
:
update_sdf
=
torch
.
zeros_like
(
sdf
[
0
:
1
])
max_sdf
=
sdf
.
max
()
min_sdf
=
sdf
.
min
()
update_sdf
[:,
self
.
geometry
.
center_indices
]
+=
(
1.0
-
min_sdf
)
# greater than zero
update_sdf
[:,
self
.
geometry
.
boundary_indices
]
+=
(
-
1
-
max_sdf
)
# smaller than zero
new_sdf
=
torch
.
zeros_like
(
sdf
)
for
i_batch
in
range
(
zero_surface
.
shape
[
0
]):
if
zero_surface
[
i_batch
]:
new_sdf
[
i_batch
:
i_batch
+
1
]
+=
update_sdf
update_mask
=
(
new_sdf
==
0
).
float
()
# Regulraization here is used to push the sdf to be a different sign (make it not fully positive or fully negative)
sdf_reg_loss
=
torch
.
abs
(
sdf
).
mean
(
dim
=-
1
).
mean
(
dim
=-
1
)
sdf_reg_loss
=
sdf_reg_loss
*
zero_surface
.
float
()
sdf
=
sdf
*
update_mask
+
new_sdf
*
(
1
-
update_mask
)
# Step 4: Here we remove the gradient for the bad sdf (full positive or full negative)
final_sdf
=
[]
final_def
=
[]
for
i_batch
in
range
(
zero_surface
.
shape
[
0
]):
if
zero_surface
[
i_batch
]:
final_sdf
.
append
(
sdf
[
i_batch
:
i_batch
+
1
].
detach
())
final_def
.
append
(
deformation
[
i_batch
:
i_batch
+
1
].
detach
())
else
:
final_sdf
.
append
(
sdf
[
i_batch
:
i_batch
+
1
])
final_def
.
append
(
deformation
[
i_batch
:
i_batch
+
1
])
sdf
=
torch
.
cat
(
final_sdf
,
dim
=
0
)
deformation
=
torch
.
cat
(
final_def
,
dim
=
0
)
return
sdf
,
deformation
,
sdf_reg_loss
,
weight
def
get_geometry_prediction
(
self
,
planes
=
None
):
'''
Function to generate mesh with give triplanes
:param planes: triplane features
'''
# Step 1: first get the sdf and deformation value for each vertices in the tetrahedon grid.
sdf
,
deformation
,
sdf_reg_loss
,
weight
=
self
.
get_sdf_deformation_prediction
(
planes
)
v_deformed
=
self
.
geometry
.
verts
.
unsqueeze
(
dim
=
0
).
expand
(
sdf
.
shape
[
0
],
-
1
,
-
1
)
+
deformation
tets
=
self
.
geometry
.
indices
n_batch
=
planes
.
shape
[
0
]
v_list
=
[]
f_list
=
[]
flexicubes_surface_reg_list
=
[]
# Step 2: Using marching tet to obtain the mesh
for
i_batch
in
range
(
n_batch
):
verts
,
faces
,
flexicubes_surface_reg
=
self
.
geometry
.
get_mesh
(
v_deformed
[
i_batch
],
sdf
[
i_batch
].
squeeze
(
dim
=-
1
),
with_uv
=
False
,
indices
=
tets
,
weight_n
=
weight
[
i_batch
].
squeeze
(
dim
=-
1
),
is_training
=
self
.
training
,
)
flexicubes_surface_reg_list
.
append
(
flexicubes_surface_reg
)
v_list
.
append
(
verts
)
f_list
.
append
(
faces
)
flexicubes_surface_reg
=
torch
.
cat
(
flexicubes_surface_reg_list
).
mean
()
flexicubes_weight_reg
=
(
weight
**
2
).
mean
()
return
v_list
,
f_list
,
sdf
,
deformation
,
v_deformed
,
(
sdf_reg_loss
,
flexicubes_surface_reg
,
flexicubes_weight_reg
)
def
get_texture_prediction
(
self
,
planes
,
tex_pos
,
hard_mask
=
None
):
'''
Predict Texture given triplanes
:param planes: the triplane feature map
:param tex_pos: Position we want to query the texture field
:param hard_mask: 2D silhoueete of the rendered image
'''
tex_pos
=
torch
.
cat
(
tex_pos
,
dim
=
0
)
if
not
hard_mask
is
None
:
tex_pos
=
tex_pos
*
hard_mask
.
float
()
batch_size
=
tex_pos
.
shape
[
0
]
tex_pos
=
tex_pos
.
reshape
(
batch_size
,
-
1
,
3
)
###################
# We use mask to get the texture location (to save the memory)
if
hard_mask
is
not
None
:
n_point_list
=
torch
.
sum
(
hard_mask
.
long
().
reshape
(
hard_mask
.
shape
[
0
],
-
1
),
dim
=-
1
)
sample_tex_pose_list
=
[]
max_point
=
n_point_list
.
max
()
expanded_hard_mask
=
hard_mask
.
reshape
(
batch_size
,
-
1
,
1
).
expand
(
-
1
,
-
1
,
3
)
>
0.5
for
i
in
range
(
tex_pos
.
shape
[
0
]):
tex_pos_one_shape
=
tex_pos
[
i
][
expanded_hard_mask
[
i
]].
reshape
(
1
,
-
1
,
3
)
if
tex_pos_one_shape
.
shape
[
1
]
<
max_point
:
tex_pos_one_shape
=
torch
.
cat
(
[
tex_pos_one_shape
,
torch
.
zeros
(
1
,
max_point
-
tex_pos_one_shape
.
shape
[
1
],
3
,
device
=
tex_pos_one_shape
.
device
,
dtype
=
torch
.
float32
)],
dim
=
1
)
sample_tex_pose_list
.
append
(
tex_pos_one_shape
)
tex_pos
=
torch
.
cat
(
sample_tex_pose_list
,
dim
=
0
)
tex_feat
=
torch
.
utils
.
checkpoint
.
checkpoint
(
self
.
synthesizer
.
get_texture_prediction
,
planes
,
tex_pos
,
use_reentrant
=
False
,
)
if
hard_mask
is
not
None
:
final_tex_feat
=
torch
.
zeros
(
planes
.
shape
[
0
],
hard_mask
.
shape
[
1
]
*
hard_mask
.
shape
[
2
],
tex_feat
.
shape
[
-
1
],
device
=
tex_feat
.
device
)
expanded_hard_mask
=
hard_mask
.
reshape
(
hard_mask
.
shape
[
0
],
-
1
,
1
).
expand
(
-
1
,
-
1
,
final_tex_feat
.
shape
[
-
1
])
>
0.5
for
i
in
range
(
planes
.
shape
[
0
]):
final_tex_feat
[
i
][
expanded_hard_mask
[
i
]]
=
tex_feat
[
i
][:
n_point_list
[
i
]].
reshape
(
-
1
)
tex_feat
=
final_tex_feat
return
tex_feat
.
reshape
(
planes
.
shape
[
0
],
hard_mask
.
shape
[
1
],
hard_mask
.
shape
[
2
],
tex_feat
.
shape
[
-
1
])
def
render_mesh
(
self
,
mesh_v
,
mesh_f
,
cam_mv
,
render_size
=
256
):
'''
Function to render a generated mesh with nvdiffrast
:param mesh_v: List of vertices for the mesh
:param mesh_f: List of faces for the mesh
:param cam_mv: 4x4 rotation matrix
:return:
'''
return_value_list
=
[]
for
i_mesh
in
range
(
len
(
mesh_v
)):
return_value
=
self
.
geometry
.
render_mesh
(
mesh_v
[
i_mesh
],
mesh_f
[
i_mesh
].
int
(),
cam_mv
[
i_mesh
],
resolution
=
render_size
,
hierarchical_mask
=
False
)
return_value_list
.
append
(
return_value
)
return_keys
=
return_value_list
[
0
].
keys
()
return_value
=
dict
()
for
k
in
return_keys
:
value
=
[
v
[
k
]
for
v
in
return_value_list
]
return_value
[
k
]
=
value
mask
=
torch
.
cat
(
return_value
[
'mask'
],
dim
=
0
)
hard_mask
=
torch
.
cat
(
return_value
[
'hard_mask'
],
dim
=
0
)
tex_pos
=
return_value
[
'tex_pos'
]
depth
=
torch
.
cat
(
return_value
[
'depth'
],
dim
=
0
)
normal
=
torch
.
cat
(
return_value
[
'normal'
],
dim
=
0
)
return
mask
,
hard_mask
,
tex_pos
,
depth
,
normal
def
forward_geometry
(
self
,
planes
,
render_cameras
,
render_size
=
256
):
'''
Main function of our Generator. It first generate 3D mesh, then render it into 2D image
with given `render_cameras`.
:param planes: triplane features
:param render_cameras: cameras to render generated 3D shape
'''
B
,
NV
=
render_cameras
.
shape
[:
2
]
# Generate 3D mesh first
mesh_v
,
mesh_f
,
sdf
,
deformation
,
v_deformed
,
sdf_reg_loss
=
self
.
get_geometry_prediction
(
planes
)
# Render the mesh into 2D image (get 3d position of each image plane)
cam_mv
=
render_cameras
run_n_view
=
cam_mv
.
shape
[
1
]
antilias_mask
,
hard_mask
,
tex_pos
,
depth
,
normal
=
self
.
render_mesh
(
mesh_v
,
mesh_f
,
cam_mv
,
render_size
=
render_size
)
tex_hard_mask
=
hard_mask
tex_pos
=
[
torch
.
cat
([
pos
[
i_view
:
i_view
+
1
]
for
i_view
in
range
(
run_n_view
)],
dim
=
2
)
for
pos
in
tex_pos
]
tex_hard_mask
=
torch
.
cat
(
[
torch
.
cat
(
[
tex_hard_mask
[
i
*
run_n_view
+
i_view
:
i
*
run_n_view
+
i_view
+
1
]
for
i_view
in
range
(
run_n_view
)],
dim
=
2
)
for
i
in
range
(
planes
.
shape
[
0
])],
dim
=
0
)
# Querying the texture field to predict the texture feature for each pixel on the image
tex_feat
=
self
.
get_texture_prediction
(
planes
,
tex_pos
,
tex_hard_mask
)
background_feature
=
torch
.
ones_like
(
tex_feat
)
# white background
# Merge them together
img_feat
=
tex_feat
*
tex_hard_mask
+
background_feature
*
(
1
-
tex_hard_mask
)
# We should split it back to the original image shape
img_feat
=
torch
.
cat
(
[
torch
.
cat
(
[
img_feat
[
i
:
i
+
1
,
:,
render_size
*
i_view
:
render_size
*
(
i_view
+
1
)]
for
i_view
in
range
(
run_n_view
)],
dim
=
0
)
for
i
in
range
(
len
(
tex_pos
))],
dim
=
0
)
img
=
img_feat
.
clamp
(
0
,
1
).
permute
(
0
,
3
,
1
,
2
).
unflatten
(
0
,
(
B
,
NV
))
antilias_mask
=
antilias_mask
.
permute
(
0
,
3
,
1
,
2
).
unflatten
(
0
,
(
B
,
NV
))
depth
=
-
depth
.
permute
(
0
,
3
,
1
,
2
).
unflatten
(
0
,
(
B
,
NV
))
# transform negative depth to positive
normal
=
normal
.
permute
(
0
,
3
,
1
,
2
).
unflatten
(
0
,
(
B
,
NV
))
out
=
{
'img'
:
img
,
'mask'
:
antilias_mask
,
'depth'
:
depth
,
'normal'
:
normal
,
'sdf'
:
sdf
,
'mesh_v'
:
mesh_v
,
'mesh_f'
:
mesh_f
,
'sdf_reg_loss'
:
sdf_reg_loss
,
}
return
out
def
forward
(
self
,
images
,
cameras
,
render_cameras
,
render_size
:
int
):
# images: [B, V, C_img, H_img, W_img]
# cameras: [B, V, 16]
# render_cameras: [B, M, D_cam_render]
# render_size: int
B
,
M
=
render_cameras
.
shape
[:
2
]
planes
=
self
.
forward_planes
(
images
,
cameras
)
out
=
self
.
forward_geometry
(
planes
,
render_cameras
,
render_size
=
render_size
)
return
{
'planes'
:
planes
,
**
out
}
def
extract_mesh
(
self
,
planes
:
torch
.
Tensor
,
use_texture_map
:
bool
=
False
,
texture_resolution
:
int
=
1024
,
**
kwargs
,
):
'''
Extract a 3D mesh from FlexiCubes. Only support batch_size 1.
:param planes: triplane features
:param use_texture_map: use texture map or vertex color
:param texture_resolution: the resolution of texure map
'''
assert
planes
.
shape
[
0
]
==
1
device
=
planes
.
device
# predict geometry first
mesh_v
,
mesh_f
,
sdf
,
deformation
,
v_deformed
,
sdf_reg_loss
=
self
.
get_geometry_prediction
(
planes
)
vertices
,
faces
=
mesh_v
[
0
],
mesh_f
[
0
]
if
not
use_texture_map
:
# query vertex colors
vertices_tensor
=
vertices
.
unsqueeze
(
0
)
vertices_colors
=
self
.
synthesizer
.
get_texture_prediction
(
planes
,
vertices_tensor
).
clamp
(
0
,
1
).
squeeze
(
0
).
cpu
().
numpy
()
vertices_colors
=
(
vertices_colors
*
255
).
astype
(
np
.
uint8
)
return
vertices
.
cpu
().
numpy
(),
faces
.
cpu
().
numpy
(),
vertices_colors
# use x-atlas to get uv mapping for the mesh
ctx
=
dr
.
RasterizeCudaContext
(
device
=
device
)
uvs
,
mesh_tex_idx
,
gb_pos
,
tex_hard_mask
=
xatlas_uvmap
(
self
.
geometry
.
renderer
.
ctx
,
vertices
,
faces
,
resolution
=
texture_resolution
)
tex_hard_mask
=
tex_hard_mask
.
float
()
# query the texture field to get the RGB color for texture map
tex_feat
=
self
.
get_texture_prediction
(
planes
,
[
gb_pos
],
tex_hard_mask
)
background_feature
=
torch
.
zeros_like
(
tex_feat
)
img_feat
=
torch
.
lerp
(
background_feature
,
tex_feat
,
tex_hard_mask
)
texture_map
=
img_feat
.
permute
(
0
,
3
,
1
,
2
).
squeeze
(
0
)
return
vertices
,
faces
,
uvs
,
mesh_tex_idx
,
texture_map
\ No newline at end of file
InstantMesh/src/models/renderer/__init__.py
0 → 100644
View file @
63bde97a
# SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
InstantMesh/src/models/renderer/synthesizer.py
0 → 100644
View file @
63bde97a
# ORIGINAL LICENSE
# SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# Modified by Jiale Xu
# The modifications are subject to the same license as the original.
import
itertools
import
torch
import
torch.nn
as
nn
from
.utils.renderer
import
ImportanceRenderer
from
.utils.ray_sampler
import
RaySampler
class
OSGDecoder
(
nn
.
Module
):
"""
Triplane decoder that gives RGB and sigma values from sampled features.
Using ReLU here instead of Softplus in the original implementation.
Reference:
EG3D: https://github.com/NVlabs/eg3d/blob/main/eg3d/training/triplane.py#L112
"""
def
__init__
(
self
,
n_features
:
int
,
hidden_dim
:
int
=
64
,
num_layers
:
int
=
4
,
activation
:
nn
.
Module
=
nn
.
ReLU
):
super
().
__init__
()
self
.
net
=
nn
.
Sequential
(
nn
.
Linear
(
3
*
n_features
,
hidden_dim
),
activation
(),
*
itertools
.
chain
(
*
[[
nn
.
Linear
(
hidden_dim
,
hidden_dim
),
activation
(),
]
for
_
in
range
(
num_layers
-
2
)]),
nn
.
Linear
(
hidden_dim
,
1
+
3
),
)
# init all bias to zero
for
m
in
self
.
modules
():
if
isinstance
(
m
,
nn
.
Linear
):
nn
.
init
.
zeros_
(
m
.
bias
)
def
forward
(
self
,
sampled_features
,
ray_directions
):
# Aggregate features by mean
# sampled_features = sampled_features.mean(1)
# Aggregate features by concatenation
_N
,
n_planes
,
_M
,
_C
=
sampled_features
.
shape
sampled_features
=
sampled_features
.
permute
(
0
,
2
,
1
,
3
).
reshape
(
_N
,
_M
,
n_planes
*
_C
)
x
=
sampled_features
N
,
M
,
C
=
x
.
shape
x
=
x
.
contiguous
().
view
(
N
*
M
,
C
)
x
=
self
.
net
(
x
)
x
=
x
.
view
(
N
,
M
,
-
1
)
rgb
=
torch
.
sigmoid
(
x
[...,
1
:])
*
(
1
+
2
*
0.001
)
-
0.001
# Uses sigmoid clamping from MipNeRF
sigma
=
x
[...,
0
:
1
]
return
{
'rgb'
:
rgb
,
'sigma'
:
sigma
}
class
TriplaneSynthesizer
(
nn
.
Module
):
"""
Synthesizer that renders a triplane volume with planes and a camera.
Reference:
EG3D: https://github.com/NVlabs/eg3d/blob/main/eg3d/training/triplane.py#L19
"""
DEFAULT_RENDERING_KWARGS
=
{
'ray_start'
:
'auto'
,
'ray_end'
:
'auto'
,
'box_warp'
:
2.
,
'white_back'
:
True
,
'disparity_space_sampling'
:
False
,
'clamp_mode'
:
'softplus'
,
'sampler_bbox_min'
:
-
1.
,
'sampler_bbox_max'
:
1.
,
}
def
__init__
(
self
,
triplane_dim
:
int
,
samples_per_ray
:
int
):
super
().
__init__
()
# attributes
self
.
triplane_dim
=
triplane_dim
self
.
rendering_kwargs
=
{
**
self
.
DEFAULT_RENDERING_KWARGS
,
'depth_resolution'
:
samples_per_ray
//
2
,
'depth_resolution_importance'
:
samples_per_ray
//
2
,
}
# renderings
self
.
renderer
=
ImportanceRenderer
()
self
.
ray_sampler
=
RaySampler
()
# modules
self
.
decoder
=
OSGDecoder
(
n_features
=
triplane_dim
)
def
forward
(
self
,
planes
,
cameras
,
render_size
=
128
,
crop_params
=
None
):
# planes: (N, 3, D', H', W')
# cameras: (N, M, D_cam)
# render_size: int
assert
planes
.
shape
[
0
]
==
cameras
.
shape
[
0
],
"Batch size mismatch for planes and cameras"
N
,
M
=
cameras
.
shape
[:
2
]
cam2world_matrix
=
cameras
[...,
:
16
].
view
(
N
,
M
,
4
,
4
)
intrinsics
=
cameras
[...,
16
:
25
].
view
(
N
,
M
,
3
,
3
)
# Create a batch of rays for volume rendering
ray_origins
,
ray_directions
=
self
.
ray_sampler
(
cam2world_matrix
=
cam2world_matrix
.
reshape
(
-
1
,
4
,
4
),
intrinsics
=
intrinsics
.
reshape
(
-
1
,
3
,
3
),
render_size
=
render_size
,
)
assert
N
*
M
==
ray_origins
.
shape
[
0
],
"Batch size mismatch for ray_origins"
assert
ray_origins
.
dim
()
==
3
,
"ray_origins should be 3-dimensional"
# Crop rays if crop_params is available
if
crop_params
is
not
None
:
ray_origins
=
ray_origins
.
reshape
(
N
*
M
,
render_size
,
render_size
,
3
)
ray_directions
=
ray_directions
.
reshape
(
N
*
M
,
render_size
,
render_size
,
3
)
i
,
j
,
h
,
w
=
crop_params
ray_origins
=
ray_origins
[:,
i
:
i
+
h
,
j
:
j
+
w
,
:].
reshape
(
N
*
M
,
-
1
,
3
)
ray_directions
=
ray_directions
[:,
i
:
i
+
h
,
j
:
j
+
w
,
:].
reshape
(
N
*
M
,
-
1
,
3
)
# Perform volume rendering
rgb_samples
,
depth_samples
,
weights_samples
=
self
.
renderer
(
planes
.
repeat_interleave
(
M
,
dim
=
0
),
self
.
decoder
,
ray_origins
,
ray_directions
,
self
.
rendering_kwargs
,
)
# Reshape into 'raw' neural-rendered image
if
crop_params
is
not
None
:
Himg
,
Wimg
=
crop_params
[
2
:]
else
:
Himg
=
Wimg
=
render_size
rgb_images
=
rgb_samples
.
permute
(
0
,
2
,
1
).
reshape
(
N
,
M
,
rgb_samples
.
shape
[
-
1
],
Himg
,
Wimg
).
contiguous
()
depth_images
=
depth_samples
.
permute
(
0
,
2
,
1
).
reshape
(
N
,
M
,
1
,
Himg
,
Wimg
)
weight_images
=
weights_samples
.
permute
(
0
,
2
,
1
).
reshape
(
N
,
M
,
1
,
Himg
,
Wimg
)
out
=
{
'images_rgb'
:
rgb_images
,
'images_depth'
:
depth_images
,
'images_weight'
:
weight_images
,
}
return
out
def
forward_grid
(
self
,
planes
,
grid_size
:
int
,
aabb
:
torch
.
Tensor
=
None
):
# planes: (N, 3, D', H', W')
# grid_size: int
# aabb: (N, 2, 3)
if
aabb
is
None
:
aabb
=
torch
.
tensor
([
[
self
.
rendering_kwargs
[
'sampler_bbox_min'
]]
*
3
,
[
self
.
rendering_kwargs
[
'sampler_bbox_max'
]]
*
3
,
],
device
=
planes
.
device
,
dtype
=
planes
.
dtype
).
unsqueeze
(
0
).
repeat
(
planes
.
shape
[
0
],
1
,
1
)
assert
planes
.
shape
[
0
]
==
aabb
.
shape
[
0
],
"Batch size mismatch for planes and aabb"
N
=
planes
.
shape
[
0
]
# create grid points for triplane query
grid_points
=
[]
for
i
in
range
(
N
):
grid_points
.
append
(
torch
.
stack
(
torch
.
meshgrid
(
torch
.
linspace
(
aabb
[
i
,
0
,
0
],
aabb
[
i
,
1
,
0
],
grid_size
,
device
=
planes
.
device
),
torch
.
linspace
(
aabb
[
i
,
0
,
1
],
aabb
[
i
,
1
,
1
],
grid_size
,
device
=
planes
.
device
),
torch
.
linspace
(
aabb
[
i
,
0
,
2
],
aabb
[
i
,
1
,
2
],
grid_size
,
device
=
planes
.
device
),
indexing
=
'ij'
,
),
dim
=-
1
).
reshape
(
-
1
,
3
))
cube_grid
=
torch
.
stack
(
grid_points
,
dim
=
0
).
to
(
planes
.
device
)
features
=
self
.
forward_points
(
planes
,
cube_grid
)
# reshape into grid
features
=
{
k
:
v
.
reshape
(
N
,
grid_size
,
grid_size
,
grid_size
,
-
1
)
for
k
,
v
in
features
.
items
()
}
return
features
def
forward_points
(
self
,
planes
,
points
:
torch
.
Tensor
,
chunk_size
:
int
=
2
**
20
):
# planes: (N, 3, D', H', W')
# points: (N, P, 3)
N
,
P
=
points
.
shape
[:
2
]
# query triplane in chunks
outs
=
[]
for
i
in
range
(
0
,
points
.
shape
[
1
],
chunk_size
):
chunk_points
=
points
[:,
i
:
i
+
chunk_size
]
# query triplane
chunk_out
=
self
.
renderer
.
run_model_activated
(
planes
=
planes
,
decoder
=
self
.
decoder
,
sample_coordinates
=
chunk_points
,
sample_directions
=
torch
.
zeros_like
(
chunk_points
),
options
=
self
.
rendering_kwargs
,
)
outs
.
append
(
chunk_out
)
# concatenate the outputs
point_features
=
{
k
:
torch
.
cat
([
out
[
k
]
for
out
in
outs
],
dim
=
1
)
for
k
in
outs
[
0
].
keys
()
}
return
point_features
InstantMesh/src/models/renderer/synthesizer_mesh.py
0 → 100644
View file @
63bde97a
# ORIGINAL LICENSE
# SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# Modified by Jiale Xu
# The modifications are subject to the same license as the original.
import
itertools
import
torch
import
torch.nn
as
nn
from
.utils.renderer
import
generate_planes
,
project_onto_planes
,
sample_from_planes
class
OSGDecoder
(
nn
.
Module
):
"""
Triplane decoder that gives RGB and sigma values from sampled features.
Using ReLU here instead of Softplus in the original implementation.
Reference:
EG3D: https://github.com/NVlabs/eg3d/blob/main/eg3d/training/triplane.py#L112
"""
def
__init__
(
self
,
n_features
:
int
,
hidden_dim
:
int
=
64
,
num_layers
:
int
=
4
,
activation
:
nn
.
Module
=
nn
.
ReLU
):
super
().
__init__
()
self
.
net_sdf
=
nn
.
Sequential
(
nn
.
Linear
(
3
*
n_features
,
hidden_dim
),
activation
(),
*
itertools
.
chain
(
*
[[
nn
.
Linear
(
hidden_dim
,
hidden_dim
),
activation
(),
]
for
_
in
range
(
num_layers
-
2
)]),
nn
.
Linear
(
hidden_dim
,
1
),
)
self
.
net_rgb
=
nn
.
Sequential
(
nn
.
Linear
(
3
*
n_features
,
hidden_dim
),
activation
(),
*
itertools
.
chain
(
*
[[
nn
.
Linear
(
hidden_dim
,
hidden_dim
),
activation
(),
]
for
_
in
range
(
num_layers
-
2
)]),
nn
.
Linear
(
hidden_dim
,
3
),
)
self
.
net_deformation
=
nn
.
Sequential
(
nn
.
Linear
(
3
*
n_features
,
hidden_dim
),
activation
(),
*
itertools
.
chain
(
*
[[
nn
.
Linear
(
hidden_dim
,
hidden_dim
),
activation
(),
]
for
_
in
range
(
num_layers
-
2
)]),
nn
.
Linear
(
hidden_dim
,
3
),
)
self
.
net_weight
=
nn
.
Sequential
(
nn
.
Linear
(
8
*
3
*
n_features
,
hidden_dim
),
activation
(),
*
itertools
.
chain
(
*
[[
nn
.
Linear
(
hidden_dim
,
hidden_dim
),
activation
(),
]
for
_
in
range
(
num_layers
-
2
)]),
nn
.
Linear
(
hidden_dim
,
21
),
)
# init all bias to zero
for
m
in
self
.
modules
():
if
isinstance
(
m
,
nn
.
Linear
):
nn
.
init
.
zeros_
(
m
.
bias
)
def
get_geometry_prediction
(
self
,
sampled_features
,
flexicubes_indices
):
_N
,
n_planes
,
_M
,
_C
=
sampled_features
.
shape
sampled_features
=
sampled_features
.
permute
(
0
,
2
,
1
,
3
).
reshape
(
_N
,
_M
,
n_planes
*
_C
)
sdf
=
self
.
net_sdf
(
sampled_features
)
deformation
=
self
.
net_deformation
(
sampled_features
)
grid_features
=
torch
.
index_select
(
input
=
sampled_features
,
index
=
flexicubes_indices
.
reshape
(
-
1
),
dim
=
1
)
grid_features
=
grid_features
.
reshape
(
sampled_features
.
shape
[
0
],
flexicubes_indices
.
shape
[
0
],
flexicubes_indices
.
shape
[
1
]
*
sampled_features
.
shape
[
-
1
])
weight
=
self
.
net_weight
(
grid_features
)
*
0.1
return
sdf
,
deformation
,
weight
def
get_texture_prediction
(
self
,
sampled_features
):
_N
,
n_planes
,
_M
,
_C
=
sampled_features
.
shape
sampled_features
=
sampled_features
.
permute
(
0
,
2
,
1
,
3
).
reshape
(
_N
,
_M
,
n_planes
*
_C
)
rgb
=
self
.
net_rgb
(
sampled_features
)
rgb
=
torch
.
sigmoid
(
rgb
)
*
(
1
+
2
*
0.001
)
-
0.001
# Uses sigmoid clamping from MipNeRF
return
rgb
class
TriplaneSynthesizer
(
nn
.
Module
):
"""
Synthesizer that renders a triplane volume with planes and a camera.
Reference:
EG3D: https://github.com/NVlabs/eg3d/blob/main/eg3d/training/triplane.py#L19
"""
DEFAULT_RENDERING_KWARGS
=
{
'ray_start'
:
'auto'
,
'ray_end'
:
'auto'
,
'box_warp'
:
2.
,
'white_back'
:
True
,
'disparity_space_sampling'
:
False
,
'clamp_mode'
:
'softplus'
,
'sampler_bbox_min'
:
-
1.
,
'sampler_bbox_max'
:
1.
,
}
def
__init__
(
self
,
triplane_dim
:
int
,
samples_per_ray
:
int
):
super
().
__init__
()
# attributes
self
.
triplane_dim
=
triplane_dim
self
.
rendering_kwargs
=
{
**
self
.
DEFAULT_RENDERING_KWARGS
,
'depth_resolution'
:
samples_per_ray
//
2
,
'depth_resolution_importance'
:
samples_per_ray
//
2
,
}
# modules
self
.
plane_axes
=
generate_planes
()
self
.
decoder
=
OSGDecoder
(
n_features
=
triplane_dim
)
def
get_geometry_prediction
(
self
,
planes
,
sample_coordinates
,
flexicubes_indices
):
plane_axes
=
self
.
plane_axes
.
to
(
planes
.
device
)
sampled_features
=
sample_from_planes
(
plane_axes
,
planes
,
sample_coordinates
,
padding_mode
=
'zeros'
,
box_warp
=
self
.
rendering_kwargs
[
'box_warp'
])
sdf
,
deformation
,
weight
=
self
.
decoder
.
get_geometry_prediction
(
sampled_features
,
flexicubes_indices
)
return
sdf
,
deformation
,
weight
def
get_texture_prediction
(
self
,
planes
,
sample_coordinates
):
plane_axes
=
self
.
plane_axes
.
to
(
planes
.
device
)
sampled_features
=
sample_from_planes
(
plane_axes
,
planes
,
sample_coordinates
,
padding_mode
=
'zeros'
,
box_warp
=
self
.
rendering_kwargs
[
'box_warp'
])
rgb
=
self
.
decoder
.
get_texture_prediction
(
sampled_features
)
return
rgb
InstantMesh/src/models/renderer/utils/__init__.py
0 → 100644
View file @
63bde97a
# SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
InstantMesh/src/models/renderer/utils/math_utils.py
0 → 100644
View file @
63bde97a
# MIT License
# Copyright (c) 2022 Petr Kellnhofer
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import
torch
def
transform_vectors
(
matrix
:
torch
.
Tensor
,
vectors4
:
torch
.
Tensor
)
->
torch
.
Tensor
:
"""
Left-multiplies MxM @ NxM. Returns NxM.
"""
res
=
torch
.
matmul
(
vectors4
,
matrix
.
T
)
return
res
def
normalize_vecs
(
vectors
:
torch
.
Tensor
)
->
torch
.
Tensor
:
"""
Normalize vector lengths.
"""
return
vectors
/
(
torch
.
norm
(
vectors
,
dim
=-
1
,
keepdim
=
True
))
def
torch_dot
(
x
:
torch
.
Tensor
,
y
:
torch
.
Tensor
):
"""
Dot product of two tensors.
"""
return
(
x
*
y
).
sum
(
-
1
)
def
get_ray_limits_box
(
rays_o
:
torch
.
Tensor
,
rays_d
:
torch
.
Tensor
,
box_side_length
):
"""
Author: Petr Kellnhofer
Intersects rays with the [-1, 1] NDC volume.
Returns min and max distance of entry.
Returns -1 for no intersection.
https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
"""
o_shape
=
rays_o
.
shape
rays_o
=
rays_o
.
detach
().
reshape
(
-
1
,
3
)
rays_d
=
rays_d
.
detach
().
reshape
(
-
1
,
3
)
bb_min
=
[
-
1
*
(
box_side_length
/
2
),
-
1
*
(
box_side_length
/
2
),
-
1
*
(
box_side_length
/
2
)]
bb_max
=
[
1
*
(
box_side_length
/
2
),
1
*
(
box_side_length
/
2
),
1
*
(
box_side_length
/
2
)]
bounds
=
torch
.
tensor
([
bb_min
,
bb_max
],
dtype
=
rays_o
.
dtype
,
device
=
rays_o
.
device
)
is_valid
=
torch
.
ones
(
rays_o
.
shape
[:
-
1
],
dtype
=
bool
,
device
=
rays_o
.
device
)
# Precompute inverse for stability.
invdir
=
1
/
rays_d
sign
=
(
invdir
<
0
).
long
()
# Intersect with YZ plane.
tmin
=
(
bounds
.
index_select
(
0
,
sign
[...,
0
])[...,
0
]
-
rays_o
[...,
0
])
*
invdir
[...,
0
]
tmax
=
(
bounds
.
index_select
(
0
,
1
-
sign
[...,
0
])[...,
0
]
-
rays_o
[...,
0
])
*
invdir
[...,
0
]
# Intersect with XZ plane.
tymin
=
(
bounds
.
index_select
(
0
,
sign
[...,
1
])[...,
1
]
-
rays_o
[...,
1
])
*
invdir
[...,
1
]
tymax
=
(
bounds
.
index_select
(
0
,
1
-
sign
[...,
1
])[...,
1
]
-
rays_o
[...,
1
])
*
invdir
[...,
1
]
# Resolve parallel rays.
is_valid
[
torch
.
logical_or
(
tmin
>
tymax
,
tymin
>
tmax
)]
=
False
# Use the shortest intersection.
tmin
=
torch
.
max
(
tmin
,
tymin
)
tmax
=
torch
.
min
(
tmax
,
tymax
)
# Intersect with XY plane.
tzmin
=
(
bounds
.
index_select
(
0
,
sign
[...,
2
])[...,
2
]
-
rays_o
[...,
2
])
*
invdir
[...,
2
]
tzmax
=
(
bounds
.
index_select
(
0
,
1
-
sign
[...,
2
])[...,
2
]
-
rays_o
[...,
2
])
*
invdir
[...,
2
]
# Resolve parallel rays.
is_valid
[
torch
.
logical_or
(
tmin
>
tzmax
,
tzmin
>
tmax
)]
=
False
# Use the shortest intersection.
tmin
=
torch
.
max
(
tmin
,
tzmin
)
tmax
=
torch
.
min
(
tmax
,
tzmax
)
# Mark invalid.
tmin
[
torch
.
logical_not
(
is_valid
)]
=
-
1
tmax
[
torch
.
logical_not
(
is_valid
)]
=
-
2
return
tmin
.
reshape
(
*
o_shape
[:
-
1
],
1
),
tmax
.
reshape
(
*
o_shape
[:
-
1
],
1
)
def
linspace
(
start
:
torch
.
Tensor
,
stop
:
torch
.
Tensor
,
num
:
int
):
"""
Creates a tensor of shape [num, *start.shape] whose values are evenly spaced from start to end, inclusive.
Replicates but the multi-dimensional bahaviour of numpy.linspace in PyTorch.
"""
# create a tensor of 'num' steps from 0 to 1
steps
=
torch
.
arange
(
num
,
dtype
=
torch
.
float32
,
device
=
start
.
device
)
/
(
num
-
1
)
# reshape the 'steps' tensor to [-1, *([1]*start.ndim)] to allow for broadcastings
# - using 'steps.reshape([-1, *([1]*start.ndim)])' would be nice here but torchscript
# "cannot statically infer the expected size of a list in this contex", hence the code below
for
i
in
range
(
start
.
ndim
):
steps
=
steps
.
unsqueeze
(
-
1
)
# the output starts at 'start' and increments until 'stop' in each dimension
out
=
start
[
None
]
+
steps
*
(
stop
-
start
)[
None
]
return
out
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment