@@ -206,7 +206,7 @@ def _extract_intrinsics( # noqa: C901
206
206
"The orthographic camera scale must be ((1.0, 1.0, 1.0),). "
207
207
f"{ kwargs .get ('scale_xyz' , cameras .scale_xyz )[cloud_idx ]} ."
208
208
)
209
- sensor_width = max_x - min_x
209
+ sensor_width = ( max_x - min_x ) * ( self . renderer . _renderer . width / self . renderer . _renderer . height )
210
210
if not sensor_width > 0.0 :
211
211
raise ValueError (
212
212
f"The orthographic camera must have positive size! Is: { sensor_width } ." # noqa: B950
@@ -220,24 +220,25 @@ def _extract_intrinsics( # noqa: C901
220
220
focal_length_conf = kwargs .get ("focal_length" , cameras .focal_length )[
221
221
cloud_idx
222
222
]
223
- if (
224
- focal_length_conf .numel () == 2
225
- and focal_length_conf [0 ] * self .renderer ._renderer .width
226
- - focal_length_conf [1 ] * self .renderer ._renderer .height
227
- > 1e-5
228
- ):
223
+ if torch .any (focal_length_conf <= 0.0 ):
224
+ raise ValueError (f"Pulsar requires focal lengths > 0.0. Provided: { focal_length_conf } ." )
225
+ if cameras .in_ndc ():
226
+ focal_length_conf *= self .renderer ._renderer .height / 2.0
227
+ if (focal_length_conf .numel () == 2 and abs (focal_length_conf [0 ] - focal_length_conf [1 ]) > 1e-5 ):
229
228
raise ValueError (
230
229
"Pulsar only supports a single focal length! "
231
230
"Provided: %s." % (str (focal_length_conf ))
232
231
)
233
232
if focal_length_conf .numel () == 2 :
234
- sensor_width = 2.0 / focal_length_conf [0 ]
233
+ focal_length_px = focal_length_conf [0 ]
235
234
else :
236
235
if focal_length_conf .numel () != 1 :
237
236
raise ValueError (
238
237
"Focal length not parsable: %s." % (str (focal_length_conf ))
239
238
)
240
- sensor_width = 2.0 / focal_length_conf
239
+ focal_length_px = focal_length_conf
240
+ focal_length_px /= self .renderer ._renderer .width / 2.0
241
+ sensor_width = 2.0 / focal_length_px
241
242
if "znear" not in kwargs .keys () or "zfar" not in kwargs .keys ():
242
243
raise ValueError (
243
244
"pulsar needs znear and zfar values for "
@@ -248,16 +249,19 @@ def _extract_intrinsics( # noqa: C901
248
249
zfar = kwargs ["zfar" ][cloud_idx ]
249
250
principal_point_x = (
250
251
kwargs .get ("principal_point" , cameras .principal_point )[cloud_idx ][0 ]
251
- * 0.5
252
- * self .renderer ._renderer .width
253
252
)
254
253
principal_point_y = (
255
254
kwargs .get ("principal_point" , cameras .principal_point )[cloud_idx ][1 ]
256
- * 0.5
257
- * self .renderer ._renderer .height
258
255
)
256
+ if cameras .in_ndc ():
257
+ principal_point_x *= 0.5 * self .renderer ._renderer .width * (self .renderer ._renderer .height / self .renderer ._renderer .width )
258
+ principal_point_y *= - 0.5 * self .renderer ._renderer .height
259
+ else :
260
+ principal_point_x = self .renderer ._renderer .width / 2.0 - principal_point_x
261
+ principal_point_y -= self .renderer ._renderer .height / 2.0
259
262
else :
260
263
if not isinstance (cameras , PerspectiveCameras ):
264
+ # This currently means FoVPerspectiveCameras.
261
265
# Create a virtual focal length that is closer than znear.
262
266
znear = kwargs .get ("znear" , cameras .znear )[cloud_idx ]
263
267
zfar = kwargs .get ("zfar" , cameras .zfar )[cloud_idx ]
@@ -266,7 +270,10 @@ def _extract_intrinsics( # noqa: C901
266
270
afov = kwargs .get ("fov" , cameras .fov )[cloud_idx ]
267
271
if kwargs .get ("degrees" , cameras .degrees ):
268
272
afov *= math .pi / 180.0
269
- sensor_width = math .tan (afov / 2.0 ) * 2.0 * focal_length
273
+ aspect_ratio = kwargs .get ("aspect_ratio" , cameras .aspect_ratio )[cloud_idx ]
274
+ if aspect_ratio != 1.0 :
275
+ raise ValueError (f"Pulsar only supports aspect ration 1.0! Provided: { aspect_ratio } ." )
276
+ sensor_width = math .tan (afov / 2.0 ) * 2.0 * focal_length * (self .renderer ._renderer .width / self .renderer ._renderer .height )
270
277
if not (
271
278
kwargs .get ("aspect_ratio" , cameras .aspect_ratio )[cloud_idx ]
272
279
- self .renderer ._renderer .width / self .renderer ._renderer .height
@@ -286,10 +293,13 @@ def _extract_intrinsics( # noqa: C901
286
293
focal_length_conf = kwargs .get ("focal_length" , cameras .focal_length )[
287
294
cloud_idx
288
295
]
296
+ if torch .any (focal_length_conf <= 0.0 ):
297
+ raise ValueError (f"Pulsar requires focal lengths > 0.0. Provided: { focal_length_conf } ." )
298
+ if cameras .in_ndc ():
299
+ focal_length_conf *= self .renderer ._renderer .height / 2.0
289
300
if (
290
301
focal_length_conf .numel () == 2
291
- and focal_length_conf [0 ] * self .renderer ._renderer .width
292
- - focal_length_conf [1 ] * self .renderer ._renderer .height
302
+ and abs (focal_length_conf [0 ] - focal_length_conf [1 ])
293
303
> 1e-5
294
304
):
295
305
raise ValueError (
@@ -312,6 +322,7 @@ def _extract_intrinsics( # noqa: C901
312
322
"Focal length not parsable: %s." % (str (focal_length_conf ))
313
323
)
314
324
focal_length_px = focal_length_conf
325
+ focal_length_px /= self .renderer ._renderer .width / 2.0
315
326
focal_length = torch .tensor (
316
327
[
317
328
znear - 1e-6 ,
@@ -322,14 +333,16 @@ def _extract_intrinsics( # noqa: C901
322
333
sensor_width = focal_length / focal_length_px * 2.0
323
334
principal_point_x = (
324
335
kwargs .get ("principal_point" , cameras .principal_point )[cloud_idx ][0 ]
325
- * 0.5
326
- * self .renderer ._renderer .width
327
336
)
328
337
principal_point_y = (
329
338
kwargs .get ("principal_point" , cameras .principal_point )[cloud_idx ][1 ]
330
- * 0.5
331
- * self .renderer ._renderer .height
332
339
)
340
+ if cameras .in_ndc ():
341
+ principal_point_x *= 0.5 * self .renderer ._renderer .width * (self .renderer ._renderer .height / self .renderer ._renderer .width )
342
+ principal_point_y *= - 0.5 * self .renderer ._renderer .height
343
+ else :
344
+ principal_point_x = self .renderer ._renderer .width / 2.0 - principal_point_x
345
+ principal_point_y -= self .renderer ._renderer .height / 2.0
333
346
focal_length = _ensure_float_tensor (focal_length , device )
334
347
sensor_width = _ensure_float_tensor (sensor_width , device )
335
348
principal_point_x = _ensure_float_tensor (principal_point_x , device )
@@ -373,7 +386,7 @@ def _extract_extrinsics(
373
386
return cam_pos , cam_rot
374
387
375
388
def _get_vert_rad (
376
- self , vert_pos , cam_pos , orthogonal_projection , focal_length , kwargs , cloud_idx
389
+ self , vert_pos , cam_pos , orthogonal_projection , focal_length , sensor_width , kwargs , cloud_idx
377
390
) -> torch .Tensor :
378
391
"""
379
392
Get point radiuses.
@@ -403,12 +416,8 @@ def _get_vert_rad(
403
416
)
404
417
else :
405
418
point_dists = torch .norm ((vert_pos - cam_pos ), p = 2 , dim = 1 , keepdim = False )
406
- vert_rad = raster_rad / focal_length .to (vert_pos .device ) * point_dists
407
- if isinstance (self .rasterizer .cameras , PerspectiveCameras ):
408
- # NDC normalization happens through adjusted focal length.
409
- pass
410
- else :
411
- vert_rad = vert_rad / 2.0 # NDC normalization.
419
+ vert_rad = raster_rad / focal_length .to (vert_pos .device ) * point_dists * sensor_width
420
+ vert_rad = vert_rad / 2.0 # NDC normalization.
412
421
return vert_rad
413
422
414
423
# point_clouds is not typed to avoid a cyclic dependency.
@@ -503,6 +512,7 @@ def forward(self, point_clouds, **kwargs) -> torch.Tensor:
503
512
cam_pos ,
504
513
orthogonal_projection ,
505
514
focal_length ,
515
+ sensor_width ,
506
516
kwargs ,
507
517
cloud_idx ,
508
518
)
0 commit comments