mirror of
https://github.com/facebookresearch/pytorch3d.git
synced 2025-08-02 03:42:50 +08:00
Fix softmax_rgb_blend() when mesh is outside zfar
Summary: This fixes two small issues with blending.py:softmax_rgb_blend(): 1) zfar and znear attributes are propagated from the camera settings instead of just using default settings of znear=1.0 and zfar=100.0 2) A check is added to prevent arithmetic overflow in softmax_rgb_blend() This is a fix in response to https://github.com/facebookresearch/pytorch3d/issues/334 where meshes rendererd using a SoftPhongShader with faces_per_pixel=1 appear black. This only occurs when the scale of the mesh is large (vertex values > 100, where 100 is the default value of zfar). This fix allows the caller to increase the value of cameras.zfar to match the scale of her/his mesh. Reviewed By: nikhilaravi Differential Revision: D23517541 fbshipit-source-id: ab8631ce9e5f2149f140b67b13eff857771b8807
This commit is contained in:
parent
6eb158e548
commit
f8ea5906c0
@ -186,7 +186,7 @@ def softmax_rgb_blend(
|
||||
z_inv = (zfar - fragments.zbuf) / (zfar - znear) * mask
|
||||
# pyre-fixme[16]: `Tuple` has no attribute `values`.
|
||||
# pyre-fixme[6]: Expected `Tensor` for 1st param but got `float`.
|
||||
z_inv_max = torch.max(z_inv, dim=-1).values[..., None]
|
||||
z_inv_max = torch.max(z_inv, dim=-1).values[..., None].clamp(min=eps)
|
||||
# pyre-fixme[6]: Expected `Tensor` for 1st param but got `float`.
|
||||
weights_num = prob_map * torch.exp((z_inv - z_inv_max) / blend_params.gamma)
|
||||
|
||||
|
@ -117,7 +117,11 @@ class SoftPhongShader(nn.Module):
|
||||
cameras=cameras,
|
||||
materials=materials,
|
||||
)
|
||||
images = softmax_rgb_blend(colors, fragments, blend_params)
|
||||
znear = kwargs.get("znear", getattr(cameras, "znear", 1.0))
|
||||
zfar = kwargs.get("zfar", getattr(cameras, "zfar", 100.0))
|
||||
images = softmax_rgb_blend(
|
||||
colors, fragments, blend_params, znear=znear, zfar=zfar
|
||||
)
|
||||
return images
|
||||
|
||||
|
||||
@ -214,7 +218,11 @@ class SoftGouraudShader(nn.Module):
|
||||
cameras=cameras,
|
||||
materials=materials,
|
||||
)
|
||||
images = softmax_rgb_blend(pixel_colors, fragments, self.blend_params)
|
||||
znear = kwargs.get("znear", getattr(cameras, "znear", 1.0))
|
||||
zfar = kwargs.get("zfar", getattr(cameras, "zfar", 100.0))
|
||||
images = softmax_rgb_blend(
|
||||
pixel_colors, fragments, self.blend_params, znear=znear, zfar=zfar
|
||||
)
|
||||
return images
|
||||
|
||||
|
||||
|
BIN
tests/data/test_simple_sphere_outside_zfar_100.png
Normal file
BIN
tests/data/test_simple_sphere_outside_zfar_100.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 758 B |
BIN
tests/data/test_simple_sphere_outside_zfar_10000.png
Normal file
BIN
tests/data/test_simple_sphere_outside_zfar_10000.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -30,6 +30,7 @@ from pytorch3d.renderer.mesh.shader import (
|
||||
HardFlatShader,
|
||||
HardGouraudShader,
|
||||
HardPhongShader,
|
||||
SoftPhongShader,
|
||||
SoftSilhouetteShader,
|
||||
TexturedSoftPhongShader,
|
||||
)
|
||||
@ -981,3 +982,63 @@ class TestRenderMeshes(TestCaseMixin, unittest.TestCase):
|
||||
)
|
||||
|
||||
self.assertClose(rgb, image_ref, atol=0.05)
|
||||
|
||||
def test_simple_sphere_outside_zfar(self):
|
||||
"""
|
||||
Test output when rendering a sphere that is beyond zfar with a SoftPhongShader.
|
||||
This renders a sphere of radius 500, with the camera at x=1500 for different
|
||||
settings of zfar. This is intended to check 1) setting cameras.zfar propagates
|
||||
to the blender and that the rendered sphere is (soft) clipped if it is beyond
|
||||
zfar, 2) make sure there are no numerical precision/overflow errors associated
|
||||
with larger world coordinates
|
||||
"""
|
||||
device = torch.device("cuda:0")
|
||||
|
||||
# Init mesh
|
||||
sphere_mesh = ico_sphere(5, device)
|
||||
verts_padded = sphere_mesh.verts_padded() * 500
|
||||
faces_padded = sphere_mesh.faces_padded()
|
||||
feats = torch.ones_like(verts_padded, device=device)
|
||||
textures = TexturesVertex(verts_features=feats)
|
||||
sphere_mesh = Meshes(verts=verts_padded, faces=faces_padded, textures=textures)
|
||||
|
||||
R, T = look_at_view_transform(1500, 0.0, 0.0)
|
||||
|
||||
# Init shader settings
|
||||
materials = Materials(device=device)
|
||||
lights = PointLights(device=device)
|
||||
lights.location = torch.tensor([0.0, 0.0, +1000.0], device=device)[None]
|
||||
|
||||
raster_settings = RasterizationSettings(
|
||||
image_size=256, blur_radius=0.0, faces_per_pixel=1
|
||||
)
|
||||
for zfar in (10000.0, 100.0):
|
||||
cameras = FoVPerspectiveCameras(
|
||||
device=device, R=R, T=T, aspect_ratio=1.0, fov=60.0, zfar=zfar
|
||||
)
|
||||
rasterizer = MeshRasterizer(
|
||||
cameras=cameras, raster_settings=raster_settings
|
||||
)
|
||||
blend_params = BlendParams(1e-4, 1e-4, (0, 0, 1.0))
|
||||
|
||||
shader = SoftPhongShader(
|
||||
lights=lights,
|
||||
cameras=cameras,
|
||||
materials=materials,
|
||||
blend_params=blend_params,
|
||||
)
|
||||
renderer = MeshRenderer(rasterizer=rasterizer, shader=shader)
|
||||
images = renderer(sphere_mesh)
|
||||
rgb = images[0, ..., :3].squeeze().cpu()
|
||||
|
||||
filename = "test_simple_sphere_outside_zfar_%d.png" % int(zfar)
|
||||
|
||||
# Load reference image
|
||||
image_ref = load_rgb_image(filename, DATA_DIR)
|
||||
|
||||
if DEBUG:
|
||||
Image.fromarray((rgb.numpy() * 255).astype(np.uint8)).save(
|
||||
DATA_DIR / ("DEBUG_" + filename)
|
||||
)
|
||||
|
||||
self.assertClose(rgb, image_ref, atol=0.05)
|
||||
|
Loading…
x
Reference in New Issue
Block a user